Я работаю с asyncio
для того, чтобы методы планирования вызывались при определенных относительных временных интервалах. Я решил централизовать планирование в один метод класса, который я написал, чтобы уменьшить вероятность получения ошибок с логикой моего проекта.Способы отделки: AttributeError: объект 'function' не имеет атрибута '__self__'?
Такой метод следует вызывать каждый раз, когда запланированный метод завершен. Я, однако, добавляю loop.call_soon
в конце каждого метода, но я решил сделать снимок decorators.
Я написал декоратор класса, а затем применил его к некоторым методам моего основного класса, написал остальную часть логики и все такое. Но при попытке проверить мои изменения в моем проекте я получаю исключение:
AttributeError: 'function' object has no attribute '__self__'
Так или иначе, украшающие мой метод сделал это функция. Это то, что я не могу понять, почему это произошло? как я могу обойти это без отказа от декораторов?
Вот минимальный, полный и проверяемый пример того, что я пытаюсь сделать:
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()
и здесь исключение я получаю:
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__'
>>>
. Обратите внимание: это может быть не совсем то, что вы действительно хотите делать. Подумайте, удалось ли украшенному методу вызвать тот же метод в другом экземпляре класса (или в поточном контексте ... где метод можно было бы вызывать параллельно в разных экземплярах). Теперь вы попадаете в неудобное состояние, в котором 'self.instance' относится к экземпляру, на который метод был вызван _last_. С учетом сказанного, это не плохой пример - я просто не хочу, чтобы люди копировали/вставляли этот код, не понимая последствий. , , – mgilson
Почему аргументы, переданные 'thinkagain .__ get__', не передаются, например,' thinkagain .__ init__' при использовании декораторов классов? – shackra
Поскольку '' '' декоратора является просто синтаксическим сахаром для 'func = decorator (dec_args) (func) (args)', если декоратор имеет собственные аргументы и 'func = decorator (func) (args)', если он этого не делает. –