关于python:装饰方法:AttributeError:’function’对象没有属性’__self__’?

Decorating methods: AttributeError: 'function' object has no attribute '__self__'?

我正在与asyncio合作,以确定在特定的相对时间间隔调用调度方法。我决定将调度集中到我编写的类的一个方法中,以减少在我的项目逻辑中出错的可能性。

每次计划方法完成时都应调用此类方法。虽然我在每个方法的末尾添加了loop.call_soon,但我决定给装饰师一个机会。

我编写了一个类修饰器,然后将它应用到我的主类的一些方法中,编写了其余的逻辑和所有这些。但是当尝试在我的项目上测试我的更改时,我得到一个例外:

1
AttributeError: 'function' object has no attribute '__self__'

不知怎么地,修饰我的方法使它成为一个函数。这是我无法理解的,为什么会这样?我怎么能在不放弃装修工人的情况下解决这个问题呢?

下面是我要做的一个最小、完整和可验证的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import asyncio
from datetime import datetime


class thinkagain:
    loop = asyncio.get_event_loop()

    def __init__(self, f):
        self.fun = f
        self.class_ = f.__self__

    def __call__(self):
        self.fun(*args, **kwords)
        # everything in Python is an object
        setattr(self.fun,"called", datetime.utcnow())
        self.loop.call_later(self.class_.think, 5 * 60)


class DoSomething:
    loop = asyncio.get_event_loop()

    @thinkagain
    def think(self):
        attr = getattr(self.dosomething,"called")
        if attr:
            elapsed = attr - datetime.utcnow()
            seconds = elapsed.seconds
        else:
            seconds = 99999

        if seconds >= 20 * 60:
            self.loop.call_soon(self.dosomething)

    @thinkagain
    def dosomething(self):
        print("I did something awesome!")

loop = asyncio.get_event_loop()
something = DoSomething()
loop.call_soon(something.think)
loop.run_forever()

我得到的例外是:

1
2
3
4
5
6
7
8
9
10
11
12
13
Python 3.5.1 (default, Dec  7 2015, 13:41:59)
[GCC 5.2.0] on linux
Type"help","copyright","credits" or"license" for more information.
>>> Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
  File"/tmp/mcve.py", line 19, in <module>
    class DoSomething:
  File"/tmp/mcve.py", line 22, in DoSomething
    @thinkagain
  File"/tmp/mcve.py", line 10, in __init__
    self.class_ = f.__self__
AttributeError: 'function' object has no attribute '__self__'
>>>


观看装饰,格雷厄姆邓布利顿高级装饰设计师的方法,探讨各种装饰风味和技术的内部实现。Highly recommended.

Relevant module he introduced at the end:https://github.com/grahamdumpleton/wrapt

我用两个版本修改你的例子。下一个版本的百叶窗属性根据你的要求直接在方法中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from datetime import datetime

class thinkagain:

    def __init__(self, f):
        # Plain function as argument to be decorated
        self.func = f

    def __get__(self, instance, owner):
        self.instance_ = instance
        return self.__call__

    def __call__(self, *args, **kwargs):
       """Invoked on every call of any decorated method"""

        # set attribute directly within bound method
        bound_method = getattr(self.instance_, self.func.__name__)
        bound_method.__dict__['called'] = datetime.utcnow()

        # returning original function with class' instance as self
        return self.func(self.instance_, *args, **kwargs)


class DoSomething_A:

    @thinkagain
    def think(self, *args, **kwargs):
        print('
%s'
% locals())
        print(self.think.called, args, kwargs)
        self.dosomething()

    @thinkagain
    def dosomething(self):
        print('%s
'
% ('-'*30), locals())
        print("%s I did something awful" % self.dosomething.called)

第二个版本的清洁剂和它的皮肤保存在方法中的属性,并直接在程序中分配。

ZZU1

两个都产生同样的愿望:

1
2
3
4
5
6
>>> something = DoSomething_A().think(1, 2)
{'args': (1, 2), 'kwargs': {}, 'self': <__main__.DoSomething_A object at     0x10209f128>}
2015-12-26 04:13:25.629887 (1, 2) {}
------------------------------
{'self': <__main__.DoSomething_A object at 0x10209f128>}
2015-12-26 04:13:25.647476 I did something awful

1
2
3
4
5
6
>>> something = DoSomething_B().think('arg_a', 'arg_b')
{'args': ('arg_a', 'arg_b'), 'kwargs': {}, 'self': <__main__.DoSomething_B object at 0x10209f208>}
2015-12-26 04:13:25.648039
------------------------------
{'self': <__main__.DoSomething_B object at 0x10209f208>}
2015-12-26 04:13:25.648390


Somehow, decorating my method made it a function.

不正确功能是创建的,然后是装饰,然后成为一种方法。你需要写一个文件,抓住self运行时的论点,然后援引实际功能。