web-dev-qa-db-ja.com

Pythonでクラスをリセットする好ましい方法

CodeReviewのこの投稿 に基づきます。

クラスFoo in Python(3)、これにはもちろん__init__()メソッドが含まれます。このクラスはいくつかのプロンプトを起動し、その処理を行います。Fooをリセットできるようにしたいので、手順を最初からやり直すことができます。

推奨される実装は何ですか?

__init__()メソッドを再度呼び出す

_def reset(self):
    self.__init__()
_

または新しいインスタンスを作成しますか?

_def reset(self):
    Foo()
_

Fooの新しいインスタンスを作成しても、resetが何度も呼び出された場合にパフォーマンスに影響する可能性のあるものが残るかどうかはわかりません。一方、すべての属性が__init__()で(再)定義されているわけではない場合、__init__()に副作用がある可能性があります。

これを行うための好ましい方法はありますか?

12
JAD

どちらも正しいですが、セマンティクスは同じ方法で実装されていません。

インスタンスをリセットできるようにするには、これを記述します(___init___は特別なメソッドであるため、___init___からカスタムメソッドを呼び出すことを好みますが、これは主に好みの問題です) :

_class Foo:
    def __init__(self):
        self.reset()
    def reset(self):
        # set all members to their initial value
_

そのように使用します:

_Foo foo      # create an instance
...
foo.reset()  # reset it
_

クラスが特別なメソッドを実装する必要がないため、ゼロから新しいインスタンスを作成するのは実際には簡単です。

_Foo foo      # create an instance
...
foo = Foo()  # make foo be a brand new Foo
_

古いインスタンスは、他で使用されていない場合、ガベージコレクションされます

両方の方法は、すべての初期化が___init___で行われるnormalクラスに使用できますが、カスタマイズされた特別なクラスには2番目の方法が必要です作成時に___new___を使用します(不変クラスなど)。


ただし、次のコードに注意してください。

_def reset(self):
    Foo()
_

will not必要なことを行います。新しいインスタンスを作成するだけで、メソッドの最後にスコープ外になるため、すぐに削除します。 self = Foo()でさえ、ローカル参照のみを設定しますが、ローカル参照はメトスの終わりに同じ範囲外になります(そして新しいインスタンスが破棄されます)。

8
Serge Ballesta

クラス属性で作業するインスタンスを保持できます。クラスをリセットするたびに、新しいインスタンスをその属性に再割り当てします。このアプローチの実装方法は次のとおりです。

_class Foo:
    instance = None    # The single instance

    def __init__(self, ...):
        # Initialize the instance if Foo.instance does not exist, else fail
        if type(self).instance is None:
            # Initialization
            type(self).instance = self
        else:
            raise RuntimeError("Only one instance of 'Foo' can exist at a time")

    @classmethod
    def reset(cls):
        cls.instance = None        # First clear Foo.instance so that __init__ does not fail
        cls.instance = Foo(...)    # Now the initialization can be called
_

その後、単に_Foo.instance_を参照するだけでインスタンスにアクセスできます。

クラスメソッドとしてresetを選択したため、_@classmethod_で装飾されています。このデコレーターを使用すると、Foo.reset()を呼び出すことでインスタンスをリセットでき、clsパラメーターがメソッドに自動的に渡されます。

私はあなたが提案するものよりもこのアプローチ(多かれ少なかれシングルトンパターンです)を好む、なぜならあなたの状況では、をしたいので、Fooの単一のインスタンスを持つことが論理的に見えるからですリセットしたがって、単一のインスタンスの使用を「強制」するのはかなり直感的です。

一方、クラスの外部にインスタンスを持ち、定義されたresetインスタンスメソッドを使用できます。

_def reset(self):
    self.__init__()
_

しかし、これはあまりうまくいかないかもしれません。 ___init___メソッド以外の属性を設定するとします。 ___init___を呼び出しても、これらの属性はリセットされません。したがって、インスタンスは期待どおりにリセットされません。単一のインスタンスを保持し、それを真新しいインスタンスに再割り当てすると、完全にクリーンになることが確実になります。

あなたが呼ぶものについて「新しいインスタンスを作成する」、それは多かれ少なかれ私が選んだものですが、問題はそれをどこに保存するかです。クラス自体を暖かくすることは理にかなっていると思います。

ちなみに、このソリューションでは、一度に1つのFooインスタンスのみが参照され、新しいインスタンスを作成すると以前の参照が逆参照されるため、パフォーマンスの問題は発生しません(「メモリリーク」など)。 1。

3
Right leg