#python #decorator
Вопрос:
В настоящее время я пытаюсь реализовать класс декоратора, чтобы отслеживать вызовы функций в классе официанта, у которого у меня есть 2 экземпляра. Я хочу, чтобы у 2 экземпляров официанта были отдельные экземпляры класса декоратора, чтобы отслеживать вызовы каждого из них, возможно ли это?
Код:
from functools import update_wrapper import time class decorater(): """ counts the number of calls and passes it into function """ def __init__(self,func): self.func = func self.num_calls = 0 update_wrapper(self, func) def __call__(self, *args, **kwargs): self.num_calls = 1 result = self.func(self.num_calls, *args, **kwargs) # passes num_calls in for seconds print(f"total runs of {self.func.__name__}: {self.num_calls}") return result class waiter(): """ waits for the number of seconds passed in """ @decorater def wait_for(seconds, var_name): time.sleep(seconds) print(f"{var_name} waited for {seconds} seconds") waiter1 = waiter() waiter2 = waiter() waiter1.wait_for("waiter1") waiter2.wait_for("waiter2")
Выход:
waiter1 waited for 1 seconds total runs of wait_for: 1 waiter2 waited for 2 seconds total runs of wait_for: 2
Желаемый результат:
waiter1 waited for 1 seconds total runs of wait_for: 1 waiter2 waited for 1 seconds total runs of wait_for: 1
Комментарии:
1. Эта структура кажется странной. Почему
wait_for
метод экземпляра, если он вообще не используетсяself
?2. О, подождите, на самом деле это не метод экземпляра, это
decorater
объект. Еще более запутанно…
Ответ №1:
Декораторы на самом деле не должны использоваться так, как вы пытаетесь их использовать, и поскольку вы уже создаете несколько экземпляров waiter
класса, почему бы просто не обработать все внутри каждого из этих экземпляров вместо использования декоратора?
Что-то вроде этого:
import time class Waiter(object): """ waits for the number of seconds passed in """ def __init__(self, name): self.name = name self.num_calls = 0 def wait(self): self.num_calls = 1 print(f"total runs of {self.num_calls}") time.sleep(self.num_calls) print(f"{self.name} waited for {self.num_calls} seconds") waiter1 = Waiter("waiter1") waiter2 = Waiter("waiter2") waiter1.wait() waiter2.wait()
Выход:
total runs of 1 waiter1 waited for 1 seconds total runs of 1 waiter2 waited for 1 seconds
Ответ №2:
Декоратором может быть любой вызываемый.
В своем коде вы использовали сам класс decorator
(а не его экземпляр) в качестве декоратора. В этом случае __init__
метод decorator
класса вызывается с оформленной функцией в качестве аргумента.
Чтобы использовать экземпляр класса в качестве декоратора, вам придется заменить украшение @decorator
на @decorator()
. Это приведет к вызову __call__
метода decorator
экземпляра с оформленной функцией в качестве аргумента. Конечно, вам придется адаптировать сигнатуру __call__
метода.
Комментарии:
1. Не могли бы вы добавить какой-нибудь код для демонстрации? Я не уверен, как это сработает.