New Python Objects (26 Nov 2002)

There's a copy of Atlas Shrugged in the library, but I'm afraid of starting a book that huge given the amount of time it might suck up. Anyone read it and wish to commend/curse it?

There was a pretty interesting discussion on comp.lang.python recently. Take the following code:

class C:
    def __getattr__ (self, x):
    	self.val = 1
	return getattr (self.val, x) 

Now calling x = C(); x + 5; returns 6 as expected. Now make C a new style Python class (by deriving it from object) and you get:

Traceback (most recent call last):
  File "", line 1, in ?
TypeError: unsupported operand types for +: 'C' and 'int' 

Alex Martelli explained things thus:

Yes it can. The idea is that operators should rely on special methods defined by the TYPE (class) of the object they're working on, NOT on special methods defined just by the OBJECT itself and not by its class. Doing otherwise (as old-style classes did, and still do for compatibility) is untenable in the general case, for example whenever you consider a class and its metaclass (given that the metaclass IS the class object's type, no more and no less).

So, for example, a + b now looks for a potential __add__ special method, NOT in a itself, but rather in type(a) [except, for compatibility, when a instances an old-style class]. I had some difficulty understanding that, early on in the lifecycle of Python 2.2, but when the notion "clicked" I saw it made a lot of sense.

So, to wrap an arbitrary object X in such a way that X's special methods will be used by any operator, you need to ensure you do the wrapping with a _class_ that exposes said special methods. That's generally easiest to do with a factory function with a nested class that uses inheritance, but you have many other choices depending on what exactly you're trying to accomplish.