Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 类方法的最小修饰符_Python_Decorator - Fatal编程技术网

Python 类方法的最小修饰符

Python 类方法的最小修饰符,python,decorator,Python,Decorator,我一开始是这样的: class Client (object): def __init__ (self): self.state = None def open (self, destination): if self.state not in [None]: raise error ... ... open stuff ... self.state = 'Open' def handle (self):

我一开始是这样的:

class Client (object):
    def __init__ (self):
        self.state = None
    def open (self, destination):
        if self.state not in [None]: raise error ...
        ... open stuff ...
        self.state = 'Open'
    def handle (self):
        if self.state not in ['Open'] raise error ...
        ... handle stuff ...
    def close (self):
        if self.state not in ['Open'] raise error ...
        ... close stuff ...
        self.state = None
    @states([None])
    def open (self, destination):
        ... open stuff ...
(我不喜欢使用单独的
\uuu init\uuu()
open()
方法,但我调用的东西需要这样做。无论如何,这不是我问题的核心。)

现在,随着方法和状态数量的增加,我想我应该重构成这样:

class Client (object):
    def __init__ (self):
        self.state = None
    def open (self, destination):
        if self.state not in [None]: raise error ...
        ... open stuff ...
        self.state = 'Open'
    def handle (self):
        if self.state not in ['Open'] raise error ...
        ... handle stuff ...
    def close (self):
        if self.state not in ['Open'] raise error ...
        ... close stuff ...
        self.state = None
    @states([None])
    def open (self, destination):
        ... open stuff ...
其他方法也是如此。基于例如,我为装饰师提出了以下定义:

from functools import wraps

def states (statelist):
    def decorator (f):
        @wraps(f)   # In order to preserve docstrings, etc.
        def wrapped (self, *args, **kwargs):
            if self.state not in statelist: raise error ...
            return f(self, *args, **kwargs)
        return wrapped
    return decorator

这相当复杂,而且还存在一个问题,即它不会被派生类继承(我的解决方案是简单地使其成为一个全局类)。我的问题是:这是这个问题的最小的、惯用的解决方案,还是我做错了什么?这是我第一次尝试定义我自己的装饰师。我找到的各种参考资料(包括指向
wrapps
)似乎向我不知情的自我暗示,这就是事实。(或者有一个漂亮的库为我封装了这种扭曲吗?快速浏览了一下
functools
,但我不能说我真的理解文档,而且无论如何,漂亮的东西似乎>=2.6,而我还需要支持Python 2.5一段时间……)

是-此解决方案非常简单,而且可读性很强

您应该这样做——另一种选择是学习“d”编程,并检查可用的Python库以使用面向方面技术——A.O.的用例是
或多或少,这就是:向所有具有共同特征的方法添加锅炉板代码。(在Python中,只需使用适当的模块,无需像Java那样为语言的超集使用替代编译器)

您可以使用状态模式:

class AlreadyClosedError(Exception): pass
class AlreadyOpenError(Exception): pass

class Client(object):

    def __init__(self):
        self._change_state(Closed)

    def _change_state(self, state):
        self.__class__ = state


class Closed(Client):

    def open(self, destination):
        # opening stuff, and if successful:
        self._change_state(Open)

    def handle(self):
        raise AlreadyClosedError()

    def close(self):
        raise AlreadyClosedError()


class Open(Client):

    def open(self, destination):
        raise AlreadyOpenError()

    def handle(self):
        """ handling stuff """

    def close(self):
        # closing stuff, and if successful:
        self._change_state(Closed)
四人帮的书以不同的方式实现了状态模式。在那里,stateful对象持有对一个状态的引用,所有相关调用都被重定向到此状态。但作者也解释说,这种有状态对象“似乎在运行时改变了它的类”。在Python中,由于其动态性,我们不需要像在动态性较差的语言中那样在运行时模拟类的更改,而是完全这样做。由于只有两个状态,这可能有点过头了,但是当您添加更多的状态和更复杂的转换规则时,它有助于保持方法的简短和简单。每个类代表对象可能处于的特定状态,如果您正确地进行了转换,您可以将其视为一个不变量。

我将其修改为:

def states(*states):
    def decorator (f):
        @wraps(f)   # In order to preserve docstrings, etc.
        def wrapped(self, *args, **kwargs):
            if self.state not in states: raise error ...
            return f(self, *args, **kwargs)
        return wrapped
    return decorator

这节省了您键入方括号。

我想您可能需要一个描述符,但我还不能将它放在我的脑海中…您可以使用它使其稍微短一点,但这样做很好。顺便说一句,如果您不满意装饰每个重写的方法,考虑使用元模型,它将描述每个方法的允许状态,并向每个状态添加状态检查代码。如果状态集和方法集不变,但方法的实现不变,这是最好的方法。@JochenRitzel:感谢您提供指向装饰器模块的指针。它还帮助我理解
functools
文档。。。我想,我同意,你所拥有的是好的。如果你想去掉括号,你可以
def states(*statelist)
,然后用
@states('Open','New')
等来装饰。我认为我不想修改我的类层次结构,因为我不希望状态的数量增长太多,我需要有一些类覆盖我目前设置的基类方法;但肯定值得为未来铭记。