Ir para o conteúdo
ou

Software livre Brasil

0 amigos

Nenhum(a)

0 comunidades

Nenhum(a)

Diego Búrigo Zacarão

 Voltar a Blog em dieg...
Tela cheia

Generic Python Decorators

1 de Agosto de 2011, 0:00 , por Software Livre Brasil - 0sem comentários ainda | Ninguém está seguindo este artigo ainda.
Visualizado 170 vezes
<p>The past days I came across a need to check specific attributes in a class instance before calling a specific method of it. I decided to use decorators, but my problem was that I needed to check different attributes and I would like to do it without duplicating code and also in an elegant way. So I started to check how I could create decorators in a generic way, to be reusable, something that would end up as the following:</p> <pre class="brush:py">class Obj(object): @need_foo def foo(self): return self._foo @need_bar def bar(self): return self._bar o=Obj() o.foo() AttributeError: Attr _foo not specified.</pre> <p>Then it turned out that I could have two possibilities. The two implementations basically do exactly the same thing, the only difference is that one is simply a function and the other one is a class based decorator that have the flexibility of all resources of a class over a function. It doesn&#8217;t mean you will always use it, but it gives you the power.</p> <pre class="brush:py">class CheckAttr(object): """ Class decorator to help checking whether an attribute of an object is set before calling the wanted (decorated) method. This class decorator must be instantiated with a 'attr' and 'message', which are respectively the attr name to be checked and the exception message in case it was not set yet. """ def __init__(self, attr, message): self.attr = attr self.message = message def __call__(self, func): def _wrapper(*args, **kwargs): if not getattr(args[0], self.attr, None): raise AttributeError(self.message) return func(*args, **kwargs) return _wrapper def check_attr(attr, message): """ Decorator to help checking whether an attribute of an object is set before calling the wanted (decorated) method of an object. This decorator must be called with a 'attr' and 'message', which are respectively the attribute name to be checked and the exception message in case it was not set yet. """ def _check_func(func): def _wrapper(*args, **kwargs): if not getattr(args[0], attr, None): raise AttributeError(message) return func(*args, **kwargs) return _wrapper return _check_func # # DECORATOR WRAPPERS # # def need_bar(func): return CheckAttr('_bar', 'Attr _bar not specified.')(func) def need_qux(func): return check_attr('_qux', 'Attr _qux not specified.')(func) </pre> <p>The code above allow us to use those two kinds of decorators in the following ways. Examples on how to invoke the code are in the docstrings as doctest:</p> <pre class="brush:py">class Obj(object): """ >>> o = Obj() >>> o.foo() Traceback (most recent call last): ... AttributeError: Attr _foo not specified. Use `bind_foo`. >>> o.bar() Traceback (most recent call last): ... AttributeError: Attr _bar not specified. >>> o.baz() Traceback (most recent call last): ... AttributeError: Attr _baz not specified. Use `bind_baz`. >>> o.qux() Traceback (most recent call last): ... AttributeError: Attr _qux not specified. """ # Calling the class based decorator directly @CheckAttr('_foo', 'Attr _foo not specified. Use `bind_foo`.') def foo(self): return self._foo def bind_foo(self, foo): self._foo = foo # Calling the class based decorator using a wrapper @need_bar def bar(self): return self._bar # Calling the function based decorator directly @check_attr('_baz', 'Attr _baz not specified. Use `bind_baz`.') def baz(self): return self._baz def bind_baz(self, baz): self._baz = baz # Calling the function based decorator using a wrapper @need_qux def qux(self): return self._qux </pre> <p>In the end I used the function based decorator with the wrappers (@need_attribute), because it was enough for what I wanted. But it&#8217;s quite obvious now to me that decorators can be used in much more powerful ways.</p>
Fonte: http://diegobz.net/2011/08/01/generic-python-decorators/

0sem comentários ainda

Enviar um comentário

Os campos são obrigatórios.

Se você é um usuário registrado, pode se identificar e ser reconhecido automaticamente.