对于方法的成员修饰符是否有更简单的语法?

2024-09-28 19:33:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我更改了一个class,它有一个必须在运行许多其他函数之前运行的函数。“优先于他人”功能现在是一个装饰器。但我提出的语法似乎非常不直观

过去是这样的:

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

Tags: inselfforreturnondefargs装饰
2条回答

乍一看,为了解决这个问题,这可能更复杂

  1. 装饰器未绑定到类的实例
  2. 此装饰器与类耦合

我将使装饰器参数化,并将其移出课堂。然后,可以将专门用于特定预调用方法的decorator实例分配给类变量。然后这个类变量可以用作实际的装饰器

def precall_decorator(precall_f):
    def decor(f):
        def inner(self, *args, **kwargs):
            precall_f(self)
            return f(self, *args, **kwargs)
        return inner
    return decor

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()
        ...

    _throttled = precall_decorator(_wait_on_throttlers)

    @_throttled
    def request1(self):
        ...

    @_throttled
    def request2(self):
        ...

下面是一个可运行的示例,演示了我的建议,即如何将decorator函数完全移出类:

from random import randint
import time


class TempoThrottler:
    def __init__(self, t):
        pass
    def isallowed(self):
 #       return [True, False](randint(0,1))
        return [True, False][randint(0,1)]
    def mustwait(self):
        return 1
    def consume(self):
        pass


# Decorator not in class.
def _throttled(f):
    def inner(self, *args, **kwargs):
        self._wait_on_throttlers()
        return f(self, *args, **kwargs)
    return inner


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()
        ...

    @_throttled
    def request1(self):
        print('in request1()')
        ...

    @_throttled
    def request2(self):
        print('in request2()')
        ...


s = Session(range(3))
s.request1()  # -> in request1()
s.request2()  # -> in request2()

相关问题 更多 >