looping wrote: > Hi, > for the fun I try operator overloading experiences and I didn't > exactly understand how it works. > > Here is my try: >>>> class myint(int): > def __pow__(self, value): > return self.__add__(value) > >>>> a = myint(3) >>>> a ** 3 > 6 > > OK, it works. Now I try different way to achieve the same result but > without much luck: > >>>> class myint(int): > pass >>>> myint.__pow__ = myint.__add__ > > or: >>>> class myint(int): > __pow__ = int.__add__ > > or: >>>> class myint(int): > pass >>>> a.__pow__ = a.__add__ > > but for every try the result was the same: >>>> a = myint(3) >>>> a ** 3 > 27 > > Why it doesn't works ? >
This may, or may not be a bug, depending on ones interpretation. int.__pow__ is a ternary operation while int.__add__ is binary. For a Python function, like def __pow__(self, ...), the interpreter can't properly check if the method takes the correct number of arguments, so accepts it without question. But since int.__add__ is a slot wrapper the interpreter can tell, and chokes. So it just falls back to using int.__pow__. Now for a more detailed explanation. Each Python type, and class, has a vtable of C function pointers for all the operations the interpreter understands. A type only defines functions for those operations it supports. The remaining pointer are null. These functions are known as slot functions, a slot being a C structure field in a Python object instance (Types are instances too!). The int type has slot functions for binary + and ternary ** for instance, but none for container []. To make the slot mechanism visible to Python, allowing operator overloading, generic wrapper slot functions and slot wrapper methods are used. When a special method, such as __add__ or __pow__, is added to a class, either in the class declaration or later by attribute assignment, the corresponding slot is set to point to a generic wrapper that will actually call the special method. When a builin type, like int, has a type specific slot function for a particular operation, a corresponding slot wrapper is added to the type that can call the slot function. So not only can one define addition for a class by having an __add__ method (via generic wrappers), but one can call the __add__ method on an int (via slot wrappers). Now for the specific case of myint. Not all slot functions are created equal. The binary + slot function takes two arguments, the ternary ** slot function three. So int's corresponding __add__ and __pow__ slot wrapper methods also differ. When subclassing int all goes well: class myint(int): pass The myint class inherits int's slot functions for arithmetic, and those functions can be called by int's slot wrappers, such as __add__ and __pow__. But the following is unexpected: myint.__pow__ = myint.__add__ Here __pow__ calls a slot function taking three arguments, __add__ calls one taking two. What follows is probably unplanned, no exception is raised. myint's ** slot function is not replaced with a generic wrapper that will call the __pow__ method. Instead myint keeps the slot function inherited from int. So myint may have a __pow__ method that adds, but it is never called when doing a **. Curiously C PyPy does what was expected: >pypy-c.exe Python 2.4.1 (pypy 1.0.0 build 41438) on win32 Type "help", "copyright", "credits" or "license" for more information. >>>> class MyInt(int): .... pass .... >>>> MyInt.__pow__ = MyInt.__add__ >>>> mi=MyInt(12) >>>> mi**2 14 >>>> Lenard Lindstrom -- http://mail.python.org/mailman/listinfo/python-list