By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
455,536 Members | 1,290 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 455,536 IT Pros & Developers. It's quick & easy.

inheritance, types, operator overload, head ache

P: n/a
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)
<type 'int'>
>>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>

Jul 7 '06 #1
Share this Question
Share on Google+
4 Replies


P: n/a
th*****@gmail.com 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:
>>b1 = Byte(1)
b1
'\x01'
>>b1.__int__()
1
>>b2 = Byte(2)
b2
'\x02'
>>b2.__int__()
2
>>b1.__int__()
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)
Jul 8 '06 #2

P: n/a
Thanks very much for the reply. I'll give that a shot and post back
with the result.

--
matthew

Bruno Desthuilliers wrote:
th*****@gmail.com 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:
>b1 = Byte(1)
b1
'\x01'
>b1.__int__()
1
>b2 = Byte(2)
b2
'\x02'
>b2.__int__()
2
>>b1.__int__()
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)
Jul 10 '06 #3

P: n/a
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)
Yes, that appears to be correct. Experiments indicated that it's an
issue with escaping.

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
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
--
matthew

Jul 11 '06 #4

P: n/a
th*****@gmail.com wrote:
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)

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

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

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
Jul 11 '06 #5

This discussion thread is closed

Replies have been disabled for this discussion.