Question

Basically I want to have access to all standard python int operators, eg __and__ and __xor__ etc, specifically whenever the result is finally printed I want it represented in Hex format. (Kind of like putting my calculator into Hex mode)

class Hex(int):
  def __repr__(self):
    return "0x%x"%self
  __str__=__repr__ # this certainly helps with printing

if __name__=="__main__":
  print Hex(0x1abe11ed) ^ Hex(440720179)
  print Hex(Hex(0x1abe11ed) ^ Hex(440720179))

Ideally BOTH line of output should be hexadecimal: 0xfacade, however the first one yields decimal: 16435934

Any ideas?

Was it helpful?

Solution

In response to your comment:

You could write a Mixin by yourself:

class IntMathMixin:
    def __add__(self, other):
        return type(self)(int(self).__add__(int(other)))
    # ... analog for the others

Then use it like this:

class Hex(IntMathMixin, int):
    def __repr__(self):
         return "0x%x"%self
    __str__=__repr__ 

OTHER TIPS

You should define __repr__ and __str__ separately:

class Hex(int):
  def __repr__(self):
    return "Hex(0x%x)" % self
  def __str__(self):
    return "0x%x" % self

The __repr__ function should (if possible) provide Python text that can be eval()uated to reconstruct the original object. On the other hand, __str__ can just return a human readable representation of the object.

A class decorator, especially in Python 2.6 and beyond, is the handiest way to wrap a lot of methods to "return an instance of this class's type rather than an instance of the superclass", which, as other have indicated, is your underlying issue (beyond quibbles with __str__ vs __repr__, worthwhile but not at all resolutory for your problem;-).

def returnthisclassfrom(specials):
  specialnames = ['__%s__' % s for s in specials.split()]
  def wrapit(cls, method):
    return lambda *a: cls(method(*a))
  def dowrap(cls):
    for n in specialnames:
      method = getattr(cls, n)
      setattr(cls, n, wrapit(cls, method))
    return cls
  return dowrap

@returnthisclassfrom('and or xor')
class Hex(int):
  def __repr__(self): return hex(self)
  __str__ = __repr__

a = Hex(2345)
b = Hex(5432)
print a, b, a^b

In Python 2.6, this emits

0x929 0x1538 0x1c11

as desired. Of course you can add more methodnames to the decorator, etc; if you're stuck with Python 2.5, remove the decorating line (the one starting with @) and use instead

class Hex(int):
  def __repr__(self): return hex(self)
  __str__ = __repr__
Hex = returnthisclassfrom('and or xor')(Hex)

a mite less elegant, but just as effective;-)

Edit: fixed an occurence of "the usual scoping issue" in the code.

You'll need to get the operators (+, -, ** etc) to return instances of Hex. As is, it will return ints, i.e.

class Hex(int):
    def __repr__(self):
        return "Hex(0x%x)" % self
    def __str__(self):
        return "0x%x" % self
>>> h1 = Hex(100)
>>> h2 = Hex(1000)
>>> h1
Hex(0x64)
>>> h2
Hex(0x3e8)
>>> h1+h2
1100
>>> type(h1+h2)
<type 'int'>

So, you can override the various operators:

class Hex(int):
    def __repr__(self):
        return "Hex(0x%x)" % self
    def __str__(self):
        return "0x%x" % self
    def __add__(self, other):
        return Hex(super(Hex, self).__add__(other))
    def __sub__(self, other):
        return self.__add__(-other)
    def __pow__(self, power):
        return Hex(super(Hex, self).__pow__(power))
    def __xor__(self, other):
        return Hex(super(Hex, self).__xor__(other))

>>> h1 = Hex(100)
>>> h2 = Hex(1000)
>>> h1+h2
Hex(0x44c)
>>> type(h1+h2)
<class '__main__.Hex'>
>>> h1 += h2
>>> h1
Hex(0x44c)
>>> h2 ** 2
Hex(0xf4240)
>>> Hex(0x1abe11ed) ^ Hex(440720179)
>>> Hex(0xfacade)

I don't know about this, I feel that there must be a better way without having to override every operator to return an instance of Hex???

Override __str__ as well.

__repr__ is used when repr(o) is called, and to display a value at the interactive prompt. __str__ is called for most instances of stringifying an object, including when it is printed.

The default __str__ behavior for an object is to fall back to the repr, but int provides its own __str__ method (which is identical to __repr__ (before Python 3), but does not fall back to __repr__).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top