Meta-class fun with PEP 318 [was Re: PEP 318 - posting draft]
Sean Ross
sross at connectmail.carleton.ca
Fri Mar 26 20:45:13 EST 2004
[snip]
> --------------------------------------------------------------------------
----
> PEP: 318
> Title: Function/Method Decorator Syntax
[snip]
> Abstract
> ========
>
> The current method for declaring class and static methods is awkward
> and can lead to code that is difficult to understand. Ideally, these
> transformations should be made at the same point in the code where the
> declaration itself is made. This PEP introduces new syntax for
> transformations of a declaration.
>
>
> Motivation
> ==========
>
> The current method of applying a transformation to a function or
> method places the actual translation after the function body. For
> large functions this separates a key component of the function's
> behavior from the definition of the rest of the function's external
> interface. For example::
>
> def foo(self):
> perform method operation
> foo = classmethod(foo)
>
> This becomes less readable with longer methods. It also seems less
> than pythonic to name the function three times for what is
> conceptually a single declaration. A solution to this problem is to
> move the transformation of the method closer to the method's own
> declaration. While the new syntax is not yet final, the intent is to
> replace::
>
> def foo(cls):
> pass
> foo = synchronized(lock)(foo)
> foo = classmethod(foo)
>
> with an alternative that places the decoration in the function's
> declaration::
>
> def foo(cls) using [synchronized(lock), classmethod]:
> pass
>
Just for fun, I thought I'd try a little meta-class hackery to bring
method decoration and method annotation (adding attributes to
a method) near/before the method declaration. This is *not*
meant as an alternative to PEP318 (for one thing, it only applies
to methods), I just wanted to see if/how it could be done.
import sys
def delayed_decorate(method, *decorators):
"Decorate method during class instantation"
for decorator in decorators:
method = decorator(method)
return method
# new syntax for this operation is being discussed on python dev ...
# e.g.,
# @author = "your name here"
def delayed_annotate(method, **attributes):
"Annotate (add attributes to) method during class instantation"
method.__dict__.update(attributes)
def annotate(funcname, **attributes):
"Mark method for delayed annotation"
clsdict = sys._getframe(1).f_locals
clsdict.setdefault("annotated", {})[funcname] = attributes
def decorate(funcname, *decorators):
"Mark method for delayed decoration"
clsdict = sys._getframe(1).f_locals
clsdict.setdefault("decorated", {})[funcname] = decorators
class MetaDecorate(type):
"Enables delayed decoration and annotation of methods"
def __new__(klass, name, bases, _dict):
if "annotated" in _dict:
for method, attrs in _dict["annotated"].iteritems():
delayed_annotate(_dict[method], **attrs)
del _dict["annotated"]
if "decorated" in _dict:
for method, decorators in _dict["decorated"].iteritems():
_dict[method] = delayed_decorate(_dict[method], *decorators)
del _dict["decorated"]
return type.__new__(klass, name, bases, _dict)
class Decorate(object):
__metaclass__ = MetaDecorate
class C(Decorate):
"Example class"
a = "A"
# You can annotate and decorate a method before it has been defined.
annotate("f", author="Sean Ross", version="0.9.1", deprecated=True)
decorate("f", classmethod)
def f(klass):
return klass.a
decorate("g", staticmethod)
def g():
return "G"
print "C.f.author =", C.f.author
print "C.f.version =", C.f.version
print "C.f() =>", C.f()
print "C.g() =>", C.g()
""" OUTPUT:
C.f.author = Sean Ross
C.f.version = 0.9.1
C.f() => A
C.g() => G
"""
Neat.
More information about the Python-list
mailing list