Are decorators really that different from metaclasses...

Bengt Richter bokr at oz.net
Wed Aug 25 12:08:06 CEST 2004


On Wed, 25 Aug 2004 13:26:03 +1000, Anthony Baxter <anthonybaxter at gmail.com> wrote:

>I forgot one other point I meant to add - think about when the body of
>a class gets executed, vs when the body of a function gets executed.
>The former is at compile time, the latter is when the function is
>used.
Actually, the body of the class gets executed after whatever code
just precedes the class def (though with a different environment, with
bindings going into the class dict), but UIAM both of those are compiled
when the combined source is compiled?

if you put the class def inside a function and dis.dis it, you get:

 >>> def foo():
 ...     class C(object):
 ...         __metaclass__ = MC
 ...         def m(self): return 'method m'
 ...     return C
 ...

Above we have *compiled* both foo and the class definition in its body, but we
have executed only the foo *definition*. (Note no complaint here about MC undefined)

 >>> import dis
 >>> dis.dis(foo)
   2           0 LOAD_CONST               1 ('C')
               3 LOAD_GLOBAL              0 (object)
               6 BUILD_TUPLE              1
               9 LOAD_CONST               2 (<code object C at 008FDF20, file "<stdin>", line 2>)

              12 MAKE_FUNCTION            0
              15 CALL_FUNCTION            0
              18 BUILD_CLASS
              19 STORE_FAST               0 (C)

   5          22 LOAD_FAST                0 (C)
              25 RETURN_VALUE
              26 LOAD_CONST               0 (None)
              29 RETURN_VALUE

Just to show when the class definition finishes:

 >>> def MC(*args): print args; return type(*args)
 ...

Now call foo to make the class *definition* in the body of foo execute (BTW triggering MC):

 >>> Cfoo = foo()
 ('C', (<type 'object'>,), {'m': <function m at 0x00903370>, '__module__': '__main__', '__metacla
 ss__': <function MC at 0x008FD4F0>})

(the printed args tuple above wrapped, obviously)

What we got:
 >>> Cfoo
 <class '__main__.C'>
 >>> Cfoo.m
 <unbound method C.m>
 >>> Cfoo().m
 <bound method C.m of <__main__.C object at 0x00901FD0>>

Regards,
Bengt Richter



More information about the Python-list mailing list