[Python-3000] yes to class decorators
tomer filiba
tomerfiliba at gmail.com
Thu Nov 16 00:06:04 CET 2006
i understand there's a green light for class decorators in py3k,
so i wanted to give the issue a slight push.
one problem with metaclasses is they are non-nestable, i.e., a
function can be wrapped by a number of decorators, while
classes can have only one metaclass.
not only that, but metaclasses complicate inheritance,
because their are not "componentized" the way decorators
are (i.e., decorator A does not impose restrictions on
how decorator B will work, whereas metaclasses must
be subclasses of one another, which means they are not
isolated *components*)
first i want to differentiate between ``metaclasses`` and
``pseudo metaclasses``. real metaclasses subclass type
and change it's behavior. pseudo metaclasses just use
the __metaclass__ magic syntax to modify the class
being returned, but not it's type (i.e., it's type is //type//)
for example -- this is what i call pseudo-metaclass:
>>> def singleton(*args):
... return type(*args)() # create the only instance
...
>>> class OnlyOne(object):
... __metaclass__ = singleton
...
>>> OnlyOne
<__main__.OnlyOne object at 0x009F5270>
of course we want to keep metaclasses as a facility as
well as a concept, but we do not want to have to use the
__metaclass__ syntax when it's not about real metaclasses.
class decorators -- like function decorators -- wrap the object
(class in this case), which makes them stackable and
componentized.
here are some usecases to class decorators:
def singleton(cls):
return cls() # create the "single instance"
@singleton
class OnlyOne(object):
pass
another example: @staticclass - automatically make all
methods staticmethods, or whatever (dotNET has them,
for instance). essentially this turns the class into a module.
def staticclass(cls):
newdict = {}
for name, obj in cls.__dict__.iteritems():
if isinstance(getattr(cls, name), MethodType):
newdict[name] = staticmethod(obj)
else:
newdict[name] = obj
return type(cls.__name__, cls.__bases__, newdict)
@staticclass
class Eggs(objects):
def foo():
print "foo"
def goo():
print "goo"
Eggs.foo()
e = Eggs()
e.goo()
i'm not saying this particular example is useful, but i have
had many times when i thought "argh, i wish i had class
decorators for that".
sadly though, i don't remember many of them, since i always
had to find workarounds :)
ANYWAY, if we went this far already, we might as well just
trash the __metaclass__ syntax (*) altogether. we can easily
implement a metaclass decorator that does the trick:
def metaclass(meta):
def wrapper(cls):
return meta(cls.__name__, cls.__bases__, dict(cls.__dict__))
return wrapper
class FooMeta(type):
....
@singleton
@metaclass(FooMeta)
class Bar(object):
....
or even something like
@FooMeta
class Bar(object):
pass
although that would require some hackery. forget it, it's better
to be explicit.
(*) throwing only the syntax. subclassing type is still required
of course, but IMHO it's much more clear to understand where
the "magic" comes from when a class has a @metaclass
decorator instead of a __metaclass__ attribute.
moreover, as shown above, we can simplify the way type_new()
works, which is a blessing on its own (considering its current
complexity)
- tomer
More information about the Python-3000
mailing list