Как создать различные экземпляры класса декоратора в python

#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. Не могли бы вы добавить какой-нибудь код для демонстрации? Я не уверен, как это сработает.