Python:强制装饰继承?
我使用的是相当大的OOP代码库,我想注入一些跟踪/日志记录。最简单的方法是在某些基类的某些方法周围引入一个decorator,但遗憾的是decorator不是继承的 我确实尝试过以下方法:Python:强制装饰继承?,python,inheritance,decorator,Python,Inheritance,Decorator,我使用的是相当大的OOP代码库,我想注入一些跟踪/日志记录。最简单的方法是在某些基类的某些方法周围引入一个decorator,但遗憾的是decorator不是继承的 我确实尝试过以下方法: def trace(fn): def wrapper(instance, *args, **kwargs): result = fn(instance, *args, **kwargs) # trace logic... return result
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
…虽然\uuuu调用
方法已包装(我可以从将实例信息打印到控制台中看到),但包装器功能未按预期执行
我还简要介绍了使用基于的元类,但它会立即破坏系统中使用内省的其他部分,因此我认为这是不可能的
有没有其他方法可以强制这些修饰符应用于继承自基类的类的\uu调用方法?你不能这样做。。。看看这里:
基本上。大多数特殊函数都是在类级别查找的。猴子在初始化后修补它不会有任何效果
也就是说,您应该能够做如下操作:
class BaseClass(object):
__call__ = trace(object.__call__)
def __init__(self, ...):
...
现在,它是在类级别包装的,所以它可以工作
编辑:这不是一个真正的答案。您想要的是:
class BaseClass(object):
@decorator
__call__ = something
class SubClass(BaseClass):
__call__ = something_else
在这种情况下。。。无论您为基类\uuuu调用\uuuu
方法放置什么,子类方法都将覆盖它。这不是关于装饰器和非装饰器的区别,而是继承的是函数(实际上是属性,因为python中没有太大区别)。decorator看起来与函数是分开的,但实际上并不是这样——在上面,decorator所做的只是将\uuu call\uuu
的定义从something
更改为decorator(something)
(它仍然必须返回一个可调用项)
然后,在子类中,将此函数重新分配给完全不同的对象
你可以使用一个类装饰器,但这些东西往往会打破你所注意到的内省;它们将类转换为返回类的函数。工厂功能也存在类似问题
也许可以查看配置文件
模块?我知道有一些较低级别的钩子,它用来跟踪函数调用等,您也可以使用它们(尽管不太了解它们)。为什么元编程会打乱内省?也许你没有正确地使用它?试试这个(假设Python2.x):
然后,您可以简单地从基类继承,而\uuuuuu调用
将自动包装
我不确定什么样的内省会打破这种局面。除非基类
实际上不是继承自对象
,而是继承自实现其自身元的东西??但是你也可以通过强制MyMeta
从父级的meta继承(而不是type
)来处理这种情况。所以你是说你想把\uu call\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu>和它的所有子级包装在基类中?@freakish:是的,有点<BaseClass
中的code>\uuuuu call\uuuu
被所有子级(其中有许多子级)覆盖,因此在\uuuu call\uuuuu
级别应用装饰器是在一个位置一致添加跟踪的最简单方法。这与您试图解决的问题相同吗,基类上的装饰器继承到子类。这已经奏效了;我认为我使用\uuuuu init\uuuu
方法导致内省失败,而\uuuu new\uuuu
在正确的点“切入”。@这很奇怪,我认为\uuuuuu init\uuu
也可以做到。我会深入研究的。虽然在元编程方面,我倾向于更频繁地使用\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
,但我认为您不需要在超类的\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu新
调用中将作为参数传递super
已经绑定了那个参数。@user2357112实际上您必须这样做。我不确定引擎盖下会发生什么,但Python会抛出一个异常。这可能与以下事实有关:\uuuuu new\uuuu
在创建实际实例之前触发(在本例中,“instance”表示“class”)。不幸的是,我的trace
版本不是评测,而是通过系统跟踪更多数据,我的观点是探查器解决了一个类似的问题——它必须包装/跟踪所有函数调用,以便为每个调用存储开始/停止时间。您需要做类似的事情,除了记录它们和/或检查参数以跟踪数据流,而不是对它们计时。
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