我正在使用相当大的OOP代码库,我想注入一些跟踪/日志记录。最简单的方法是在某些基类上引入围绕某些方法的装饰器,但遗憾的是装饰器不会被继承。
我确实尝试过以下内容:
def trace(fn):
def wrapper(instance, *args, **kwargs):
result = fn(instance, *args, **kwargs)
# trace logic...
return result
return wrapper
class BaseClass(object):
def __init__(self, ...):
...
self.__call__ = trace(self.__call__) # line added to end of method
...当__call__
方法 包装时(我可以看到将实例信息打印到控制台),wrapper
函数不会被执行为预期
我还简要介绍了如何使用基于this answer的元类,但它会立即打破使用内省的系统的其他部分,所以我认为这是不行的。
有没有其他方法可以强制应用这些装饰器围绕从__call__
继承的BaseClass
类方法?
答案 0 :(得分:3)
你做不到......看到这样的事情: Python method resolution mystery
基本上。大多数特殊功能都在 class 级别查找。初始化后对其进行修补不会产生任何影响。
那就是说,你应该可以这样做:
class BaseClass(object):
__call__ = trace(object.__call__)
def __init__(self, ...):
...
现在,它已经包含在类级别,因此它将起作用。
编辑:这不是一个真正的答案。你想要的是:
class BaseClass(object):
@decorator
__call__ = something
class SubClass(BaseClass):
__call__ = something_else
在这种情况下......无论你为BaseClass __call__
方法添加什么,SubClass方法都会覆盖它。它不是关于装饰器与非装饰器的关系,因为它是函数(嗯,实际上,属性,因为在python中没有太大的区别)是继承的。装饰器看起来与函数分开,但它们并不是真的 - 在上面,装饰器所做的就是将__call__
的定义从something
更改为{{1 (必须仍然返回一个可调用的)。
然后,在子类中,将此函数重新分配给完全不同的函数。
你可以使用类装饰器,但是当你注意到这些东西往往会破坏内省;他们把一个类变成一个返回一个类的函数。与工厂功能类似的问题。
也许看看decorator(something)
模块?我知道它有一些较低级别的钩子用于跟踪你可能也可以使用的函数调用等(虽然对它们了解不多)。
答案 1 :(得分:3)
为什么元编程会搞乱内省?也许你没有正确使用它?试试这个(假设是Python2.x):
class MyMeta(type):
def __new__(mcl, name, bases, nmspc):
if "__call__" in nmspc:
nmspc["__call__"] = trace(nmspc["__call__"])
return super(MyMeta, mcl).__new__(mcl, name, bases, nmspc)
class BaseClass(object):
__metaclass__ = MyMeta
然后,您只需继承BaseClass
,__call__
就会自动换行。
我不确定什么样的内省可以打破这种情况。除非BaseClass
实际上不继承自object
,而是来自实现其自身元的东西?但是你也可以通过强迫MyMeta
继承父父的元(而不是type
)来处理这种情况。