Decorators applied to class definition using Python

Compared to decorators applied to functions, it is not easy to understand decorators applied to a class.

@foo class Bar(object): def __init__(self, x): self.x = x def spam(self): statements 

What is the use of decorators for the class? How to use it?

+7
python decorator
source share
2 answers

It replaces the vast majority of classic useful applications for custom metaclasses much easier.

Think of it this way: nothing that directly in a class of a class can refer to an object of a class, because a class object does not exist until it is executed (this is the task of a metaclass to create a class object - usually type , for all classes without custom metaclass).

But the code in the class decoder works after creating the class object (indeed, with the class object as an argument!), And therefore it can well refer to this class object (and usually it needs to be done).

For example, consider:

 def enum(cls): names = getattr(cls, 'names', None) if names is None: raise TypeError('%r must have a class field `names` to be an `enum`!', cls.__name__) for i, n in enumerate(names): setattr(cls, n, i) return cls @enum class Color(object): names = 'red green blue'.split() 

and now you can reference Color.red , Color.green , & c, and not 0 , 1 , etc. (Of course, you usually add even more functionality to make "a enum ", but here I am just showing an easy way to add such a functional complement to the class decorator, instead of using a custom metaclass! -)

+23
source share

One use case that I can think of is if you want to wrap all class methods with a single function decorator. Let's say you have the following decorator:

 def logit(f): def res(*args, **kwargs): print "Calling %s" % f.__name__ return f(*args, **kwargs) return res 

And the following class:

 >>> class Pointless: def foo(self): print 'foo' def bar(self): print 'bar' def baz(self): print 'baz' >>> p = Pointless() >>> p.foo(); p.bar(); p.baz() foo bar baz 

You can decorate all methods:

 >>> class Pointless: @logit def foo(self): print 'foo' @logit def bar(self): print 'bar' @logit def baz(self): print 'baz' >>> p = Pointless() >>> p.foo(); p.bar(); p.baz() Calling foo foo Calling bar bar Calling baz baz 

But this is LAME! Instead, you can do this:

 >>> def logall(cls): for a in dir(cls): if callable(getattr(cls, a)): setattr(cls, a, logit(getattr(cls, a))) return cls >>> @logall class Pointless: def foo(self): print 'foo' def bar(self): print 'bar' def baz(self): print 'baz' >>> p = Pointless() >>> p.foo(); p.bar(); p.baz() Calling foo foo Calling bar bar Calling baz baz 

UPDATE: a more general version of logall :

 >>> def wrapall(method): def dec(cls): for a in dir(cls): if callable(getattr(cls, a)): setattr(cls, a, method(getattr(cls, a))) return cls return dec >>> @wrapall(logit) class Pointless: def foo(self): print 'foo' def bar(self): print 'bar' def baz(self): print 'baz' >>> p = Pointless() >>> p.foo(); p.bar(); p.baz() Calling foo foo Calling bar bar Calling baz baz >>> 

Full disclosure: I never had to do this, and I just made this example.

+6
source share

All Articles