lazy arithmetic

Simon Forman rogue_pedro at yahoo.com
Fri Aug 25 00:58:16 EDT 2006


pianomaestro at gmail.com wrote:
> # This is what I have in mind:
>
> class Item(object):
>   def __add__(self, other):
>     return Add(self, other)
>
> class Add(Item):
>   def __init__(self, a, b):
>     self.a = a
>     self.b = b
>
> a = Item()
> b = Item()
>
> c = a+b
>
> # Now, I am going absolutely crazy with this idea
> # and using it in a big way. So I'm looking at
> # automating the process. As a first step,
> # I thought maybe this would work:
>
> class Item(object):
>   pass
>
> class Add(Item):
>   def __init__(self, a, b=None):
>     print self, a, b
>     self.a = a
>     self.b = b
>
> Item.__add__ = Add
>
> x = Item()
> y = Item()
>
> print x, y
>
> c = x+y
>
> # This time, the Add constructor gets only the first two arguments:
> "self" and "y".
> # So, what happened to "x" ? Is this some kind of property voodoo going
> on ?
>
> # Simon.

Look at the signature for __add__:

__add__(self, other)

Now look at the signature for __init__:

__init__(self, a, b=None)

Now look at the output of your script:

|>>
<__main__.Item object at 0xb6faa4ac> <__main__.Item object at
0xb6faa3ec>
<__main__.Add object at 0xb6faa5ec> <__main__.Item object at
0xb6faa3ec> None


When python calls x.__add__ as a result of "x+y" it only passes it y as
'other', or, in this case, as 'a'.  The 'self' arg gets filled in with
a brand new Add instance, because __add__ (rather than being a method
of Item) is really the class Add.  (b will never be filled in using the
Add.__init__ method this way.)

Consider:

|>> x
<__main__.Item object at 0xb6f10f0c>
|>> x.__add__
<class '__main__.Add'>
|>> Badd = x.__add__
|>> Badd
<class '__main__.Add'>
|>> b = Badd(23, 18)
<__main__.Add object at 0xb6f10e8c> 23 18
|>> b
<__main__.Add object at 0xb6f10e8c>

Make more sense? :-)

"Item.__add__ = Add" is a very strange thing to do, I'm not surprised
it didn't work.

HTH,
~Simon




More information about the Python-list mailing list