Python の内部/ネストされたクラスは私を混乱させます。それらなしでは達成できないことはありますか?もしそうなら、それは何ですか?
9 に答える
これを理解できるように頭を包む必要があることがあります。ほとんどの言語では、クラス定義はコンパイラへの指示です。つまり、プログラムが実行される前にクラスが作成されます。Python では、すべてのステートメントが実行可能です。つまり、このステートメントは次のようになります。
class foo(object):
pass
は、次のように実行時に実行されるステートメントです。
x = y + z
これは、他のクラス内にクラスを作成できるだけでなく、好きな場所にクラスを作成できることを意味します。次のコードを検討してください。
def foo():
class bar(object):
...
z = bar()
したがって、「内部クラス」の概念は実際には言語構造ではありません。それはプログラマーの構造です。Guido は、これがどのように実現したかについて非常によくまとめています。しかし、本質的には、基本的な考え方は、これにより言語の文法が単純化されるということです。
クラス内でのクラスのネスト:
入れ子になったクラスはクラス定義を肥大化させ、何が起こっているのかを理解するのを難しくします。
ネストされたクラスは、テストをより困難にする結合を作成する可能性があります。
Python では、Java とは異なり、1 つのファイル/モジュールに複数のクラスを配置できるため、クラスは最上位クラスに近いままであり、クラス名の前に「_」を付けて、他のクラスを配置すべきではないことを示すことさえできます。それを使用しています。
ネストされたクラスが有用であると証明できる場所は、関数内です
def some_func(a, b, c):
class SomeClass(a):
def some_method(self):
return b
SomeClass.__doc__ = c
return SomeClass
クラスは関数から値をキャプチャし、C++ でのテンプレート メタプログラミングのようなクラスを動的に作成できます。
ネストされたクラスに対する議論は理解していますが、場合によってはそれらを使用する場合があります。双方向リンク リスト クラスを作成していて、ノードを維持するためのノード クラスを作成する必要があるとします。DoublyLinkedList クラス内に Node クラスを作成するか、DoublyLinkedList クラスの外に Node クラスを作成するかの 2 つの選択肢があります。Node クラスは DoublyLinkedList クラス内でのみ意味があるため、この場合は最初の選択を好みます。非表示/カプセル化の利点はありませんが、Node クラスが DoublyLinkedList クラスの一部であると言えるというグループ化の利点があります。
100% のテスト カバレッジに近づけるために、 Python の内部クラスを使用して、意図的にバグのあるサブクラスを unittest 関数内 (つまり 内def test_something():
) に作成しました (たとえば、いくつかのメソッドをオーバーライドして、ほとんどトリガーされないログ ステートメントをテストします)。
振り返ってみると、エドの答えに似ていますhttps://stackoverflow.com/a/722036/1101109
このような内部クラスは、それらへのすべての参照が削除されたら、範囲外になり、ガベージ コレクションの準備が整う必要があります。たとえば、次のinner.py
ファイルを使用します。
class A(object):
pass
def scope():
class Buggy(A):
"""Do tests or something"""
assert isinstance(Buggy(), A)
OSX Python 2.7.6 で次の興味深い結果が得られます。
>>> from inner import A, scope
>>> A.__subclasses__()
[]
>>> scope()
>>> A.__subclasses__()
[<class 'inner.Buggy'>]
>>> del A, scope
>>> from inner import A
>>> A.__subclasses__()
[<class 'inner.Buggy'>]
>>> del A
>>> import gc
>>> gc.collect()
0
>>> gc.collect() # Yes I needed to call the gc twice, seems reproducible
3
>>> from inner import A
>>> A.__subclasses__()
[]
ヒント - バグのあるクラスへの他の (キャッシュされた?) 参照を保持しているように見える Django モデルでこれを実行しようとしないでください。
したがって、一般的に、100% のテスト カバレッジを本当に重視し、他のメソッドを使用できない場合を除き、この種の目的で内部クラスを使用することはお勧めしません。__subclasses__()
を使用すると、内部クラスによって汚染される場合があることに注意してください。いずれにせよ、ここまで読んでいただければ、私たちはこの時点で Python にかなり深く関わっていると思います。