【发布时间】:2020-01-10 01:24:29
【问题描述】:
我更改了 class,它有一个必须在运行许多其他函数之前运行的函数。 “prior-to-others”功能现在是一个装饰器。但是我想出的语法似乎很不直观。
以前是这样的:
class Session:
def __init__(self, ts):
self.tempo_throttlers = [TempoThrottler(t) for t in ts]
...
def _wait_on_throttlers(self):
for th in self.tempo_throttlers:
if not th.isallowed():
time.sleep(th.mustwait())
th.consume()
...
def request1(self):
self._wait_on_throttlers()
...
def request2(self):
self._wait_on_throttlers()
...
现在是这样的:
class Session:
def __init__(self, ts):
self.tempo_throttlers = [TempoThrottler(t) for t in ts]
...
def _wait_on_throttlers(self):
for th in self.tempo_throttlers:
if not th.isallowed():
time.sleep(th.mustwait())
th.consume()
...
def _throttled(f):
def inner(self, *args, **kwargs):
self._wait_on_throttlers()
return f(self, *args, **kwargs)
return inner
@_throttled
def request1(self):
...
@_throttled
def request2(self):
...
而且,虽然我认为这个装饰器的使用使代码更加清晰,但这个装饰器的实现需要一些工作。它也非常脆弱且难以阅读。例如,如果将内部返回行return f(self, *args, **kwargs) 更改为return self.f(*args, **kwargs),则它将不再起作用。
这似乎与类元素的编译顺序有关。我还担心这会在未来的 Python 版本中中断。我正在使用 Python 3.6.8。
是否有一种可接受和/或推荐的方法来制作此类方法的类成员装饰器,从而减少反直觉和不那么脆弱?
为了一个最小的可重现示例,... 可以被认为是一个pass 语句,TempThrottler 类可以定义为下面(这不是实际的实现,但足以满足上面的示例):
class TempoThrottler:
def __init__(self, t):
pass
def isallowed(self):
from random import randint
return (True, False)[randint(0,1)]
def mustwait(self):
return 1
def consume(self):
pass
【问题讨论】:
-
装饰器不必在课堂上,因此将它们移出课堂可能会有所改善。
-
如果您将
f(self, ...)更改为self.f(...),它应该会中断。f在第一种情况下是对函数的引用,但在第二种情况下是属性,并且由于self没有属性'f',因此会出错。 -
@martineau 装饰器使用对象的数据。它的全部意义在于调用wait_on_throttlers。会话的节流状态是会话状态的一部分。
-
因为它通过
_wait_on_throttlers()参数调用_wait_on_throttlers(),所以它不需要在类的主体中执行它。如果它使用类中定义的任何东西但没有作为参数传递给它,那将是一个问题。 -
如果你能提供一个minimal reproducible example 我会试着给你看。为了清楚起见,我的意思是将
_throttled(f)装饰器移出课堂。_wait_on_throttlers()方法可能需要在里面说(但没有真正的代码,很难说)。
标签: python python-3.x python-decorators