Python:强制装饰继承?

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

我使用的是相当大的OOP代码库,我想注入一些跟踪/日志记录。最简单的方法是在某些基类的某些方法周围引入一个decorator,但遗憾的是decorator不是继承的

我确实尝试过以下方法:

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