Diez B. Roggisch wrote:
I understand that this is a very peculiar use of classmethods but is this error intentional? Or did I completely missed the point somewhere?
Note that this is not really related to classmethods. A similar "problem" exists if you want to use an ordinary function as a method:
>>> def g(self): print "argument: " + str(self)
>>> class A(object): pass
>>> a=A() >>> a.x = g >>> a.x <function g at 0x00B9F070>
Here you see that none of the class magic has been performed; a.x is *not* a method, but an ordinary function. It has absolutely no relation to / knowledge of the class that a belongs to. Calling a.x() leads to an exception:
>>> a.x()
Traceback (most recent call last): File "<pyshell#53>", line 1, in -toplevel- a.x() TypeError: g() takes exactly 1 argument (0 given)
And of course, if you supply an argument, everything works fine:
>>> a.x(1) argument: 1
To get the method behaviour the function needs to be associated with the class:
>>> del a.x >>> A.x = g >>> a.x <bound method A.g of <__main__.A object at 0x00B93B90>> >>> a.x() argument: <__main__.A object at 0x00B93B90> >>>
The mechanism is basically as follows (with thanks to Alex Martelli's
execellent Python in a Nutshell, Chapter 5). When a.x is being resolved,
first a.__dict__['x'] is tried. In the first case x was indeed defined in a.__dict__, and its value was returned (the function also known as g). No class magic at all. The same happened with your
classmethod foo: you get a bare classmethod, and apparently these
are not callable.
In the second case, a.__dict__ did not have a key 'x'. The lookup then
continues in a's class: A.__dict__['x']. Again it finds the function.
But when a class __dict__ lookup returns a function, the result is
first wrapped into a bound or unbound method object (depending on whether you arrived there via a.x or A.x).
So far for *how* it works. As to *why* it works like this, I don't know for sure. But my guess is that the reasoning was something as follows: if you define a function (regular or something special like a classmethod) only for an instance of a class, you obviously don't want to use it in a class context: it is -by definition- invisible to the class, or to other instances of the same class. One possible use case would be to store a callback function. And in that case you definitely don't want the class magic to happen when you reference the function.
Just my 2 cents
Regards,
Ruud
-- '@'.join('.'.join(s) for s in (['ruud','de','jong'],['tiscali','nl'])) -- http://mail.python.org/mailman/listinfo/python-list