inheritance, types, operator overload, head ache

T

thorley

I'm working with the following code. I included some tests to make it
easy to see--if you run the code--what troubles I'm having.

Can some one *please* splain me why str(obj) works but not print obj,
and why obj.__int__() works, but not int(obj). I just don't get it. :(

BTW: The reason I'm going to all this mess is that I need a Byte object
that can
* print like a byte e.g. \x00
* adds like a string (concatinates)
* does bitwise math like a byte
* coereces to an int
* works with ''.join() -- The whole reason I'm inheriting from str
* Oh yeah, and some other classes inherit from it and have sequence
like behavior

Much thanks to any that can unveil the mystery and correct my broken
understanding.

regards
--
mthorley


<code>
import struct
class Byte(str): # Implement Bytes as str for easy adding and joining
"""Byte data type

Inherits from str so join will work, but supports bitwise
operations
via operator overloading. Given a digit it uses struct to
produce
the correct string format. Given a non digit string, it
attempts to
convert it to a digit using struct.unpack, and initialize its
self
>>> b = Byte(1)
>>> b '\\x01'
>>> str(b) '\\x01'
>>> b + b '\\x01\\x01'
>>> ''.join([b,b]) '\\x01\\x01'
>>> b[0] '\\x01'
>>> for i in b: i '\\x01'
>>> b >> 8 0
>>> b << 8 256
>>> b._int 1
>>> len(b) 1
>>> type(b._int)
said:
>>> b.__int__() 1
>>> int(b) 1
>>> print b
1
"""
def __new__(self, val):
if type(val) == str and not val.isdigit():
val = struct.unpack('B', val) #ensure input is valid struct
byte
self._byte = struct.pack('B', val)
self._int = int(val)
return str.__new__(self, self._byte)

def __int__(self):
return self._int

def __lshift__(self, x):
return self._int << x

def __rshift__(self, x):
return self._int >> x

def __len__(self):
return 1


def _test():
import doctest
doctest.testmod()

if __name__ == '__main__':
_test()
</code>
 
B

Bruno Desthuilliers

(e-mail address removed) a écrit :
I'm working with the following code. I included some tests to make it
easy to see--if you run the code--what troubles I'm having.

Can some one *please* splain me why str(obj) works but not print obj,

May have something to do with escape chars... I tried with:
def __str__(self):
return repr(self)

and it did the trick for printing. Now it may have other side-effects, I
don't know.
and why obj.__int__() works, but not int(obj).

I've added tracing to __int__, and it isn't called. FWIW, str type has
no attribute __int__, so I guess there's something special in the
implementation here.
I just don't get it. :(

FWIW, you have another problem to solve:
2

cf below...

(snip)
<code>
import struct
class Byte(str): # Implement Bytes as str for easy adding and joining (snip)
def __new__(self, val):

Actually, __new__ is a static method, and it takes the class as first
argument. So...
if type(val) == str and not val.isdigit():
val = struct.unpack('B', val) #ensure input is valid struct
byte
self._byte = struct.pack('B', val)
self._int = int(val)

... since the name "self" really references the class, not the instance,
the two previous lines (re)bind *class* attributes "_byte" and "_int" to
class Byte.
return str.__new__(self, self._byte)

What you want here is to first create the instance, and only then bind
to it:

def __new__(cls, val):
if type(val) == str and not val.isdigit():
val = struct.unpack('B', val)
_byte = struct.pack('B', val)
self = str.__new__(cls, _byte)
self._byte = _byte
self._int = int(val)
return self

(snip)
 
T

thorley

Thanks very much for the reply. I'll give that a shot and post back
with the result.
 
T

thorley

Yes, that appears to be correct. Experiments indicated that it's an
issue with escaping.


Oh, I see. I tried that and it worked well, but the broken int(obj) is
too annoying. I've decided to just implement the needed str methods
myself, and inherit from object. This means join will be broken, so
I'll have to do ''.join(map(str, (b0, b1))), which, for my purposes is
probably the best compromise.

Thanks again
 
G

Georg Brandl

Yes, that appears to be correct. Experiments indicated that it's an
issue with escaping.



Oh, I see. I tried that and it worked well, but the broken int(obj) is
too annoying.

The problem is that int() checks if the argument is a string (which includes
subclasses) and directly tries to convert the string without looking at
__int__. If you want, you can report this as a bug and see if other
developers agree.

Georg
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top