Classmethods are evil

Bruno Desthuilliers bruno.42.desthuilliers at websiteburo.invalid
Tue May 20 06:16:59 EDT 2008


Ivan Illarionov a écrit :
> On Mon, 19 May 2008 13:53:31 -0700, bruno.desthuilliers at gmail.com wrote:
> 
>> On 17 mai, 11:50, Ivan Illarionov <ivan.illario... at gmail.com> wrote:
>(snip)
>>> How did I come to this:http://code.djangoproject.com/changeset/7098
>>>
>>> I measured this and there was a marginal speed increase when
>>> classmethods wher moved to metaclass.
>> IIRC (please correct me if I'm wrong), this part of code is only called
>> when the class is created - in which case it makes sense to move it
>> where it belongs, ie to the metaclass. This is by no mean a use case for
>> classmethods.
> 
> Yes, this is not the use case for class methods, but they where used 
> there. 

Don't blame the tool for being misused.

> The whole point of my post was to say that classmethods are used 
> in a wrong way too often

I think it's the first time I see such a misuse of classmethods, and I 
have read quite a lot of (sometimes pretty hairy) Python code.

>  and most of Python programmers don't know that 
> the same thing can be implemented with metaclass methods.

I'd say that most Python programmers using metaclasses know when to use 
a metaclass method and when to use a classmethod. One case of (slight) 
misuse is certainly not enough to infer a general rule, and that doesn't 
make classmethods bad in anyway. And while we're at it, I'd consider 
using a custom metaclass only to implement the equivalent of a 
classmethod a misuse too - and in this case, kind of a WTF.

As a last point, there's at least one very big difference between a 
metaclass method and a classmethod, which is that you cannot call a 
metaclass method on an instance:

class MyMeta(type):
     def bar(cls):
         print "%s.bar()" % cls

class Foo(object):
     __metaclass__ = MyMeta

     @classmethod
     def baaz(cls):
         print "%s.baaz()" % cls

Foo.baaz()
Foo.bar()

f = Foo()
f.baaz()
f.bar()

=>

<class '__main__.Foo'>.baaz()
<class '__main__.Foo'>.bar()
<class '__main__.Foo'>.baaz()
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "/tmp/python-18506gCT.py", line 17, in <module>
     f.bar()
AttributeError: 'Foo' object has no attribute 'bar'

I've had use case where I needed to call classmethods on instances, 
using a metaclass method would have required an explicit call, ie 
type(obj).some_method() instead of obj.some_method(), which would have 
uselessly exposed this knowledge to client code.






More information about the Python-list mailing list