qué puede parametros ejemplo depurar decoradores decorador cómo código con python design-patterns

puede - Implementando el patrón de decorador en Python



qué es un decorador en python (6)

Como una adición a la respuesta de Philipp; si necesita no solo decorar, sino conservar el tipo de un objeto, Python le permite crear una subclase de una instancia en tiempo de ejecución:

class foo(object): def f1(self): print "original f1" def f2(self): print "original f2" class foo_decorator(object): def __new__(cls, decoratee): cls = type(''decorated'', (foo_decorator, decoratee.__class__), decoratee.__dict__) return object.__new__(cls) def f1(self): print "decorated f1" super(foo_decorator, self).f1() u = foo() v = foo_decorator(u) v.f1() v.f2() print ''isinstance(v, foo) =='', isinstance(v, foo)

Esto es un poco más complicado de lo estrictamente necesario para su ejemplo, donde sabe que la clase está decorada con anticipación.

Esto podría ser suficiente:

class foo_decorator(foo): def __init__(self, decoratee): self.__dict__.update(decoratee.__dict__) def f1(self): print "decorated f1" super(foo_decorator, self).f1()

Quiero implementar el patrón de decorador en Python, y me pregunto si hay una manera de escribir un decorador que simplemente implemente la función que quiere modificar, sin escribir placa de caldera para todas las funciones que se remiten al objeto decorado. Al igual que:

class foo(object): def f1(self): print "original f1" def f2(self): print "original f2" class foo_decorator(object): def __init__(self, decoratee): self._decoratee = decoratee def f1(self): print "decorated f1" self._decoratee.f1() def f2(self): # I would like to leave that part out self._decoratee.f2()

Me gustaría que las llamadas a foo_decorator.f2 envíen a decoratee.f2 automáticamente. ¿Hay alguna manera de escribir un método genérico que envíe todas las llamadas de funciones no implementadas a decoratee ?


El diagrama de UML en el artículo de Wikipedia vinculado está mal, al igual que su código.

Si sigue el "patrón de decorador", la clase de decorador se deriva de la clase decorada de base. (En el diagrama UML, falta una flecha de herencia de WindowDecorator a Window).

con

class foo_decorator(foo):

no es necesario que implemente métodos no decorados.

Por cierto: en los lenguajes de caracteres fuertes hay una razón más, por qué el decorador debe derivarse de la clase decorada: De lo contrario, no sería capaz de encadenar decoradores.


En uno de mis proyectos, también tuve que hacer una cosa en particular, es que incluso el objeto subyacente debería ejecutar el método que se reimplementó en el decorador. En realidad, es bastante fácil de hacer si sabes dónde dirigirte.

El caso de uso es:

  • Tengo un objeto X con los métodos A y B.
  • Creé una clase de decorador Y que anula a A.
  • Si instanciamos Y (X) y llamo A, usará A decorado como se esperaba.
  • Si B llama a A, entonces si hago una instancia de Y (X) y llamo B en el decorador, la llamada desde dentro de B va a la antigua A en el objeto original que no era deseable. Quiero que el viejo B llame al nuevo A también.

Es posible llegar a este comportamiento de esta manera:

import inspect import six # for handling 2-3 compatibility class MyBaseDecorator(object): def __init__(self, decorated): self.decorated = decorated def __getattr__(self, attr): value = getattr(self.decorated, attr) if inspect.ismethod(value): function = six.get_method_function(value) value = function.__get__(self, type(self)) return value class SomeObject(object): def a(self): pass def b(self): pass class MyDecorator(MyBaseDecorator): def a(self): pass decorated = MyDecorator(SomeObject())

Puede que esto no salga de la caja ya que escribí todo lo demás aparte del método getattr de la parte superior de mi cabeza.

El código busca el atributo solicitado en el objeto decorado, y si es un método (no funciona ahora para las propiedades, pero el cambio para apoyarlas no debería ser demasiado difícil), el código saca la función real del método y el uso de la invocación de la interfaz del descriptor "revuelve" la función como un método, pero en el decorador. Luego se devuelve y lo más probable es que se ejecute.

El efecto de esto es que si b alguna vez llama al objeto original, cuando el objeto está decorado y hay una llamada al método proveniente del decorador, el decorador se asegura de que todos los métodos accedidos estén vinculados al decorador, por lo tanto buscar cosas usando el decorador y no el objeto original, por lo tanto los métodos especificados en el decorador tienen prioridad.

PD: Sí, sé que se parece mucho a la herencia, pero esto se hace en el sentido de composición de múltiples objetos.


Para complementar la respuesta de @Alec Thomas. Modifiqué su respuesta para seguir el patrón del decorador. De esta forma, no es necesario que conozcas la clase que estás decorando por adelantado.

class Decorator(object): def __new__(cls, decoratee): cls = type(''decorated'', (cls, decoratee.__class__), decoratee.__dict__) return object.__new__(cls)

Entonces, puedes usarlo como:

class SpecificDecorator(Decorator): def f1(self): print "decorated f1" super(foo_decorator, self).f1() class Decorated(object): def f1(self): print "original f1" d = SpecificDecorator(Decorated()) d.f1()


Podría decirse que no es la mejor práctica, pero puede agregar funcionalidad a las instancias, como he hecho para ayudar a la transición de mi código desde el ORM de Django a SQLAlachemy, de la siguiente manera:

def _save(self): session.add(self) session.commit() setattr(Base,''save'',_save)


Podrías usar __getattr__ :

class foo(object): def f1(self): print "original f1" def f2(self): print "original f2" class foo_decorator(object): def __init__(self, decoratee): self._decoratee = decoratee def f1(self): print "decorated f1" self._decoratee.f1() def __getattr__(self, name): return getattr(self._decoratee, name) u = foo() v = foo_decorator(u) v.f1() v.f2()