inheritance, types, operator overload, head ache

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • thorley@gmail.com

    #1

    inheritance, types, operator overload, head ache

    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__(sel f, 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>

  • Bruno Desthuilliers

    #2
    Re: inheritance, types, operator overload, head ache

    thorley@gmail.c om 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__(sel f, 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)

    Comment

    • thorley@gmail.com

      #3
      Re: inheritance, types, operator overload, head ache

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

      --
      matthew

      Bruno Desthuilliers wrote:
      thorley@gmail.c om 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__(sel f, 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)

      Comment

      • thorley@gmail.com

        #4
        Re: inheritance, types, operator overload, head ache

        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

        Comment

        • Georg Brandl

          #5
          Re: inheritance, types, operator overload, head ache

          thorley@gmail.c om 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

          Comment

          Working...