Friday, January 06, 2006

how well do you know python, part 10

Take Alex Martelli's Number class from the augmented assignment example in What's New in Python 2.0:

class Number:
    def __init__(self, value):
        self.value = value
    def __iadd__(self, increment):
     return Number( self.value + increment)

>>> n = Number(5)
>>> n
<__main__.Number instance at 0x00356B70>

That's not very pretty. Let's add a __getattr__ method and leverage all those nice methods from the int or float or whatever it's initialized with:

class Number:
    def __init__(self, value):
        self.value = value
    def __iadd__(self, increment):
     return Number( self.value + increment)
    def __getattr__(self, attr):
        return getattr(self.value, attr)

>>> n = Number(5)
>>> n
5

Great, the __str__ method from our int is being used. Let's keep going with the example now:

>>> n += 3
>>> n.value
Traceback (most recent call last):
  File "", line 1, in ?
AttributeError: 'int' object has no attribute 'value'

What happened here?


Extra bonus unrelated mini-question to celebrate the 10th installment of HWDYKP:

Given the following code,

class Foo: pass
Bar = Foo

What do you predict is the result of the following expressions:

isinstance(Bar(), Foo)
isinstance(Foo(), Bar)

2 comments:

Anonymous said...

Number's __iadd__ method is never called. The argument is first coerced to an integer, which calls the self.value.__coerce__, which, in turn, returns a real integer. It is that integer which is incremented and re-assigned to n. n is no longer a Number at all.

The others both print True.

Simon Percivall said...

Of course, had Number been a new-style class, n.value would have worked.