如何使用python在可调用装饰器对象中引用对象实例? 背景:

如何使用python在可调用装饰器对象中引用对象实例? 背景:,python,python-2.7,decorator,scoping,Python,Python 2.7,Decorator,Scoping,我希望能够装饰功能,以便我可以跟踪他们的统计数据。使用post作为参考,我开始尝试创建自己的可调用装饰器对象 以下是我的结论: def Stats(fn): Class StatsObject(object): def __init__(self, fn): self.fn = fn self.stats = {} def __call__(self, obj, *args, **kwargs):

我希望能够装饰功能,以便我可以跟踪他们的统计数据。使用post作为参考,我开始尝试创建自己的可调用装饰器对象

以下是我的结论:

def Stats(fn):
    Class StatsObject(object):
        def __init__(self, fn):
            self.fn = fn
            self.stats = {}

        def __call__(self, obj, *args, **kwargs):
            self.stats['times_called'] = self.stats.get('times_called', 0) + 1
            return self.fn(obj, *args, **kwargs)

    function = StatsObject(fn)
    def wrapper(self, *args **kwargs):
        return function(self, *args, **kwargs)
    return wrapper

Class MockClass(object):
    @Stats
    def mock_fn(self, *args, **kwargs):
        # do things
问题: 这实际上正确地调用了mock_fn函数,但在包装器函数之外没有对stats对象的引用。i、 e.我不能做:

mc = MockClass()
mc.mock_fn()
mc.mock_fn.stats
# HasNoAttribute Exception
然后我尝试更改以下代码,认识到这是一个范围问题:

发件人:

致:

但是我当然丢失了自引用(self成为StatsObject实例,obj成为第一个参数,MockClass对象自引用丢失)


因此,我理解为什么会发生第一个问题,而不是第二个问题。是否有任何方法可以将MockClass的自引用传递给StatsObject
\uuuu call\uuu
函数?

函数本身实际上可以在Python中具有属性

def Stats(fn):
    class StatsObject(object):
        def __init__(self, fn):
            self.fn = fn
            self.stats = {}

        def __call__(self, obj, *args, **kwargs):
            self.stats['times_called'] = self.stats.get('times_called', 0) + 1
            return self.fn(obj, *args, **kwargs)

    function = StatsObject(fn)
    def wrapper(self, *args **kwargs):
        return function(self, *args, **kwargs)

    # KEY LINE BELOW: make the StatsObject available outside as "stats_fn"
    wrapper.stats_fn = function

    return wrapper

class MockClass(object):
    @Stats
    def mock_fn(self, *args, **kwargs):
        # do things
关键的一行是将
StatsObject
实例(您可能误导地将其局部命名为
function
)指定为从装饰程序返回的函数的属性


执行此操作后,
self.mock\u fn.stats\u fn.stats
(而不是
self.mock\u fn()
!该属性位于函数上,而不是其返回值)将在
MockClass
的实例中工作,并且
MockClass.mock\u fn.stats\u fn.stats
将在外部可用。统计信息将覆盖所有
MockClass
(因为decorator只调用一次,而不是每个实例调用一次),这可能是您想要的,也可能不是您想要的。

这是一个很好的响应!我知道函数是对象,但在写这篇文章时我完全忘记了这一点。但是我很好奇,当它被传递到第二个示例中时,
self
会发生什么。当我加载pdb时,我注意到在第二个示例中(我刚刚从decorator返回了可调用对象),self成为StatsObject引用,obj参数成为mock_fn的第一个参数。MockClass作用域中的自引用将消失。@它不会更改值!在
wrapper
内部,
self
MockClass
的一个实例。因此,如果需要每个实例的统计信息,可以保留嵌套的dict
stats[mockclass\u instance]['times\u called']
。您正在将该实例作为
obj
参数传递给
StatsObject.\uu调用\uu
。抱歉,我刚刚编辑了我的响应;但是你说的话让我很高兴。谢谢
    function = StatsObject(fn)
    return function
def Stats(fn):
    class StatsObject(object):
        def __init__(self, fn):
            self.fn = fn
            self.stats = {}

        def __call__(self, obj, *args, **kwargs):
            self.stats['times_called'] = self.stats.get('times_called', 0) + 1
            return self.fn(obj, *args, **kwargs)

    function = StatsObject(fn)
    def wrapper(self, *args **kwargs):
        return function(self, *args, **kwargs)

    # KEY LINE BELOW: make the StatsObject available outside as "stats_fn"
    wrapper.stats_fn = function

    return wrapper

class MockClass(object):
    @Stats
    def mock_fn(self, *args, **kwargs):
        # do things