The magic of metaclasses in Python

by shabda on November 21, 2009

Metaclasses are a way for you to have a class act as the template for another class. They are simlar to a classfactory, in that they create new classes. In words of Tim Peters Metaclasses are deeper magic than 99% of people are going to need.

However, in right hands they can be a potent tool, in particular Django uses metaclasses beautifully to create very beautiful declarative models. Without further ado, here is a very simple (and very wrong) metaclass example.

class Z(type):
    def __new__(cls, name, bases, attrs, ):
        print cls, name, bases, attrs

class A(object):
    __metaclass__ = Z


print A
print A()

Running this gives this output.

shabda@shabda-laptop ~/docs> python testmetaclass.py 
<class '__main__.Z'> A (<type 'object'>,) {'__module__': '__main__', '__metaclass__': <class '__main__.Z'>}
None
Traceback (most recent call last):
  File "testmetaclass.py", line 14, in <module>
    print A()
TypeError: 'NoneType' object is not callable

Let what happened,

  1. print cls, name, bases, attrs got executed, even though we are not creating Z or calling it anywhere.
  2. print A printed None
  3. print A() failed with a traceback

Lets try a slightly modified file,http://uswaretech.com/blog/2009/11/the-magic-of-metaclasses-in-python/

class Z(type):
    def __new__(cls, name, bases, attrs, ):
        return str

class A(object):
    __metaclass__ = Z

This gives me,

print A
print A('Hello')

shabda@shabda-laptop ~/docs> python testmetaclass.py 
<type 'str'>
Hello
shabda@shabda-laptop ~/docs> 

The output suggests that A is behaving like str. This should lead us to a few conclusions,

  1. If a class has a __metaclass__, it is replaced by another class.
  2. The function called for creating the new class is __new__, it takes 4 parameters.
  3. cls is the metaclass being called, name is the name of the original class, bases are bases for original class, and attrs are attributes from original class.
  4. The old class is set to the value returned from __metaclass__.__new__
  5. As we returned nothing in the first snippet, A was set to None. In second snippet it was set to str.

Here is an actual metaclass being used by Django.

  1. In line 24, Form. __metaclass__ is set to DeclarativeFieldsMetaclass
  2. DeclarativeFieldsMetaclass is a subclass of type.
  3. It defines a method called as __new__ which returns the newly created class.

And that is all there is to metaclasses!


This is the first in the series of short and sweet Django posts we are going to do. You are interested, right. Do follow us on twitter or subscribe to our feed.


We build Amazing We Apps. Talk to us or email us at sales@uswaretech.com .

Related posts:

  1. Python metaclasses and how Django uses them
  2. Understanding DateTime, tzinfo, timedelta & TimeZone Conversions in python
  3. Beginning python
  4. Better Python package management using source and version control systems
  5. Constraint programming in Python

12 Comments 18 Tweets

{ 1 trackback }

cychong's me2DAY
November 27, 2009 at 1:53 am

{ 25 comments… read them below or add one }

8 must_submit_this_pic November 21, 2009 at 3:31 pm

Brain hurting ouch

This comment was originally posted on Reddit

9 dwdwdw2 November 21, 2009 at 4:52 pm

Metaclasses are objects that can be used to customize class creation, they are not used as "templates" for the objects they create. The fact they can be abused to create "nice syntax" for things like defining database models is a side effect of their function. In the case of every ORM I’ve seen that abuses metaclasses, you are left with a chunk of the implementation that can’t be accessed cleanly without using Python syntax. This leaves you with few options if you want to build a new class at runtime, usually by putting a class definition in a function, something like: def make_class(…): class Foo(SomeMagicClass): someFixedName = … return Foo This is bad enough already, but as you can see, there is no convenient way to chose "someFixedName" at runtime. So you might end up with: def make_class(…): eval(”’ class %s(SomeMagicClass): %s = … return Foo ”’ % (name, someFixedName), globals(), locals()) return locals()[name] Alternatively your solution might include a simpler second interface for building things at runtime, but this is just worse. Two interfaces for doing the same thing, depending on when you happen to do it?

This comment was originally posted on Reddit

11 nextofpumpkin November 21, 2009 at 6:11 pm

tl;dr metaclasses suck. DONT USE THEM. etc.

This comment was originally posted on Reddit

12 luckystarr November 21, 2009 at 6:46 pm

Stay clear of metaclasses. Use class decorators instead!

This comment was originally posted on Reddit

13 uriel November 21, 2009 at 7:37 pm

I use python regularly, and I must say metaclasses are one of the most stupid programming language concepts introduced in quite some time. As if the multiple-inheritance python object model was not broken and painful enough already, that they had to make it about a dozen magnitude orders more complex… *sigh* If I wanted to show off at how ’smart’ I am by using byzantine features, I would use C++, thank you very much.

This comment was originally posted on Reddit

15 ubernostrum November 22, 2009 at 4:06 am

Metaclasses are not something to be used lightly, especially since factory functions and (in 2.6+) class decorators let you accomplish almost all the same things in a much cleaner fashion. Or, more generally, if you’re wondering whether you need metaclasses, you don’t. When you really need the feature, you’ll know because all the other things you’ll have tried first will have failed to do what you needed.

This comment was originally posted on Reddit

16 erikw November 22, 2009 at 4:37 am

But there are differences between class decorators and metaclasses as noted in [this PyCon paper (PDF!)](http://us.pycon.org/media/2009/talkdata/PyCon2009/055/decos_and_metas_pycon.pdf). Also [this blog](http://jackdied.blogspot.com/2008/09/pycon-uk-class-decorators-radically.html) has a useful part in the discussions on the concept that "decorators are once and metaclasses are always".

This comment was originally posted on Reddit

17 erikw November 22, 2009 at 3:43 am

As noted by Tim Peters: "Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don’t." I have programmed in python for > 10 years, and I’ve never missed this particular feature. However it is one of those things that you really want bad if you need it.

This comment was originally posted on Reddit

18 uriel November 22, 2009 at 4:48 am

> However it is one of those things that you really want bad if you need it. That is what the people that like to feel smug and smarter than everyone else likes to claim, I have seen zero real evidence of it being true.

This comment was originally posted on Reddit

21 uriel November 23, 2009 at 11:45 am

And *amen* to that. Metaclasses are evil and stupid, stay away from them.

This comment was originally posted on Reddit

23 jawbroken November 23, 2009 at 7:34 pm

you are dumb

This comment was originally posted on Reddit

24 uriel November 23, 2009 at 11:21 pm

I know, thank you for the compliment.

This comment was originally posted on Reddit

Leave a Comment

Additional comments powered by BackType

Previous post:

Next post: