resueltos programacion otra multiple metodos metodo llamar interaccion herencia entre ejercicios clases clase python wrapping

python - programacion - ¿Cómo envolver todos los métodos de una clase?



metodos en python (4)

¿Quiere decir establecer programáticamente un contenedor a los métodos de una clase? Bueno, esta es probablemente una muy mala práctica, pero aquí es cómo puede hacerlo:

def wrap_methods( cls, wrapper ): for key, value in cls.__dict__.items( ): if hasattr( value, ''__call__'' ): setattr( cls, key, wrapper( value ) )

Si tienes clase, por ejemplo.

class Test( ): def fire( self ): return True def fire2( self ): return True

y una envoltura

def wrapper( fn ): def result( *args, **kwargs ): print ''TEST'' return fn( *args, **kwargs ) return result

entonces llamando

wrap_methods( Test, wrapper )

aplicará wrapper a todos los métodos definidos en la clase Test . Utilizar con precaución! En realidad, ¡no lo uses en absoluto!

Me gustaría envolver todos los métodos de una clase en particular en Python, y me gustaría hacerlo editando el código de la clase como mínimo. ¿Cómo debo hacer esto?


El uso de decoradores de Python es el método más limpio para hacerlo, ya que parece que desea depurar o al menos rastrear el código que aparece.


Si la modificación extensa del comportamiento predeterminado de la clase es el requisito, las Clases de Meta son el camino a seguir. Aquí hay un enfoque alternativo.

Si su caso de uso se limita a simplemente envolver los métodos de instancia de una clase, podría intentar anular el método mágico __getattribute__ .

from functools import wraps def wrapper(func): @wraps(func) def wrapped(*args, **kwargs): print "Inside Wrapper. calling method %s now..."%(func.__name__) return func(*args, **kwargs) return wrapped

Asegúrate de usar functools.wraps al crear envoltorios, incluso más si el envoltorio está diseñado para la depuración, ya que proporciona TraceBacks sensatos.

import types class MyClass(object): # works only for new-style classes def method1(self): return "Inside method1" def __getattribute__(self, name): attr = super(MyClass, self).__getattribute__(name) if type(attr) == types.MethodType: attr = wrapper(attr) return attr


Una forma elegante de hacerlo se describe en el blog Voidspace de Michael Foord en una entrada sobre qué son las metaclases y cómo usarlas en la sección titulada Un método para decorar una metaclase . Simplificarlo ligeramente y aplicarlo a tu situación resultó en esto:

from types import FunctionType from functools import wraps def wrapper(method): @wraps(method) def wrapped(*args, **kwrds): # ... <do something to/with "method" or the result of calling it> return wrapped class MetaClass(type): def __new__(meta, classname, bases, classDict): newClassDict = {} for attributeName, attribute in classDict.items(): if isinstance(attribute, FunctionType): # replace it with a wrapped version attribute = wrapper(attribute) newClassDict[attributeName] = attribute return type.__new__(meta, classname, bases, newClassDict) class MyClass(object): __metaclass__ = MetaClass # wrap all the methods def method1(self, ...): # ...etc ...

En Python, los decoradores de funciones / métodos son simplemente envoltorios de funciones más un poco de azúcar sintáctico para que usarlos sea más fácil (y más bonito).

Actualización de compatibilidad de Python 3

El código anterior utiliza la sintaxis de metaclase de Python 2.x, que debería traducirse para poder usarse en Python 3.x, sin embargo, ya no funcionará en la versión anterior. Esto significa que necesitaría usar:

class MyBase(metaclass=MetaClass) ...

en lugar de:

class MyBase(object): __metaclass__ = MetaClass" ...

Si lo desea, es posible escribir código que sea compatible con Python 2.xy 3.x, pero hacerlo requiere una técnica un poco más complicada que crea dinámicamente una nueva clase base que hereda la metaclase deseada, evitando así errores debidos a Las diferencias de sintaxis entre las dos versiones de Python. Esto es básicamente lo que hace la función with_metaclass() los six módulos de Benjamin Peterson.

from types import FunctionType from functools import wraps def wrapper(method): @wraps(method) def wrapped(*args, **kwrds): print(''{!r} executing''.format(method.__name__)) return method(*args, **kwrds) return wrapped class MetaClass(type): def __new__(meta, classname, bases, classDict): newClassDict = {} for attributeName, attribute in classDict.items(): if isinstance(attribute, FunctionType): # replace it with a wrapped version attribute = wrapper(attribute) newClassDict[attributeName] = attribute return type.__new__(meta, classname, bases, newClassDict) def with_metaclass(meta): """ Create an empty class with the supplied bases and metaclass. """ return type.__new__(meta, "TempBaseClass", (object,), {}) if __name__ == ''__main__'': # Inherit metaclass from a dynamically-created base class. class MyClass(with_metaclass(MetaClass)): @staticmethod def a_static_method(): pass @classmethod def a_class_method(cls): pass def a_method(self): pass instance = MyClass() instance.a_static_method() # Not decorated. instance.a_class_method() # Not decorated. instance.a_method() # -> ''a_method'' executing