2

私はこのようなものから始めました:

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

__init__()(別のメソッドを持つことに満足していませんopen()が、私が呼び出すものはこのようにする必要があります.とにかく、それは私の質問の中心ではありません.)

現在、メソッドと状態の数が増えているため、次のようにリファクタリングする必要があると考えました。

    @states([None])
    def open (self, destination):
        ... open stuff ...

他の方法についても同様です。たとえば、この古典的な SO の回答に基づいて、デコレータの次の定義を思いつきました。

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

これはかなり複雑で、派生クラスに継承されないという問題もあります (私の解決策は単純にグローバルにすることでした)。私の質問は次のとおりです。これは、この問題に対する最小限の慣用的な解決策ですか、それとも何か間違ったことをしていますか? 独自のデコレータを定義しようとするのはこれが初めてです。私が見つけたさまざまな参考文献 (これを私に指摘したものwrapsを含む) は、これが実際にどうあるべきかを知らない自分に示唆しているようです. (または、この種のゆがみをカプセル化する気の利いたライブラリがありますか?ざっと見ましfunctoolsたが、ドキュメントを本当に理解しているとは言えません。とにかく、気の利いたものは> = 2.6のようですが、サポートする必要がありますまだしばらくPython 2.5 ...)

4

3 に答える 3

2

私はそれを次のように変更します:

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

これにより、角かっこを入力する手間が省けます。

于 2012-09-25T20:58:23.903 に答える
2

はい - この解決策は可能な限りシンプルで、読みやすいものです。

あなたはそれに行くべきです - 別の方法は、「アスペクト指向」プログラミングについて学び、アスペクト指向を使用するために利用可能なPythonライブラリをチェックすることです - AOのユースケースは多かれ少なかれこれです:共通の特性。(そして Python では、適切なモジュールを使用するだけの問題であり、Java のように言語のスーパーセットに別のコンパイラを使用する必要はありません)

于 2012-09-25T19:35:14.017 に答える
1

State パターンを使用できます。

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)

ギャング オブ フォーの本では、状態パターンを別の方法で実装しています。そこでは、ステートフル オブジェクトが状態への参照を保持し、関連するすべての呼び出しがこの状態にリダイレクトされます。しかし著者は、この種のステートフル オブジェクトは「実行時にそのクラスを変更するように見える」とも説明しています。Python では、そのダイナミズムのおかげで、実行時にクラスの変更をシミュレートする必要はありません。動的でない言語で行う必要があるのとは異なり、代わりに正確にそれを行います。状態が 2 つしかないのはやり過ぎかもしれませんが、状態を追加して遷移規則が複雑になると、メソッドを短くシンプルに保つのに役立ちます。すべてのクラスは、オブジェクトが取り得る特定の状態を表しており、遷移が正しく行われていれば、これを不変条件として扱うことができます。

于 2012-09-25T20:50:52.667 に答える