web-dev-qa-db-ja.com

Pythonで別のクラス内にクラスを定義することには利点がありますか?

ここで話しているのは、ネストされたクラスです。基本的に、モデリングしている2つのクラスがあります。 DownloadManagerクラスとDownloadThreadクラス。ここでの明らかなOOPコンセプトは合成です。ただし、合成は必ずしもネストを意味するわけではありませんか?

次のようなコードがあります。

class DownloadThread:
    def foo(self):
        pass

class DownloadManager():
    def __init__(self):
        dwld_threads = []
    def create_new_thread():
        dwld_threads.append(DownloadThread())

しかし今、私は入れ子が良い状況があるのだろうかと思っています。何かのようなもの:

class DownloadManager():
    class DownloadThread:
        def foo(self):
            pass
    def __init__(self):
        dwld_threads = []
    def create_new_thread():
        dwld_threads.append(DownloadManager.DownloadThread())
90
fuentesjr

これは、「内部」クラスが1回限りであり、外部クラスのdefinitionの外部では決して使用されない場合に行うことができます。たとえば、メタクラスを使用するには、行うのが便利な場合があります

class Foo(object):
    class __metaclass__(type):
        .... 

メタクラスを一度だけ使用する場合は、メタクラスを個別に定義する代わりに。

このようなネストされたクラスを使用したのは、それ以外の場合は、密接に関連するクラスのグループをグループ化するための名前空間としてのみ外部クラスを使用しました。

class Group(object):
    class cls1(object):
       ...

    class cls2(object):
       ...

次に、別のモジュールからGroupをインポートし、Group.cls1、Group.cls2などと呼ぶことができます。ただし、モジュールを使用することで、まったく同じ(おそらく混乱が少ない方法で)を達成できると主張するかもしれません。

108
dF.

私はPythonを知らないが、あなたの質問は非常に一般的だ。 Pythonに固有の場合は無視してください。

クラスのネストは、スコープに関するものです。あるクラスが別のクラスのコンテキストでのみ意味があると考える場合、前者はおそらくネストされたクラスになるのに適した候補です。

これは、ヘルパークラスをプライベートなネストされたクラスにする一般的なパターンです。

18
André Chalella

メタクラスを扱っている場合を除いて、これを行うメリットは実際にはありません。

クラス:スイートは本当にあなたが思っているものではありません。それは奇妙なスコープであり、奇妙なことをします。クラスを作ることすらありません!クラスの名前、ベース、属性の小さな辞書、メタクラスなど、いくつかの変数を収集する方法にすぎません。

名前、ディクショナリ、およびベースはすべて、メタクラスである関数に渡され、class:suiteがあったスコープ内の変数「name」に割り当てられます。

メタクラスをいじって、実際に標準のクラス内にクラスをネストすることで得られるものは、コードを読むのが難しく、コードを理解するのが難しく、なぜ「クラス」スコープは、他のpythonスコープとはまったく異なります。

6
Jerub

クラスをクラスジェネレータとして使用している可能性があります。のように(いくつかのカフコードから:)

class gen(object):
    class base_1(object): pass
    ...
    class base_n(object): pass

    def __init__(self, ...):
        ...
    def mk_cls(self, ..., type):
        '''makes a class based on the type passed in, the current state of
           the class, and the other inputs to the method'''

この機能が必要になったとき、非常に明確になると思います。似たようなことをする必要がない場合は、おそらく良いユースケースではありません。

5
tim.tadh

強化された機能が特定のネストされたクラスにカプセル化された継承されたクラスを構築する場合、ネストされたクラスには別の使用法があります。

この例を参照してください。

class foo:

  class bar:
    ...  # functionalities of a specific sub-feature of foo

  def __init__(self):
    self.a = self.bar()
    ...

  ...  # other features of foo


class foo2(foo):

  class bar(foo.bar):
    ... # enhanced functionalities for this specific feature

  def __init__(self):
    foo.__init__(self)

fooのコンストラクターで、構築されるオブジェクトが実際にfooオブジェクトである場合、行self.a = self.bar()foo.barを構築し、オブジェクトが構築される場合はfoo2.barオブジェクトを構築することに注意してください実際にはfoo2オブジェクトです。

クラスbarが代わりにクラスfooの外で定義され、その継承バージョン(たとえば、bar2と呼ばれる)の場合、新しいクラスfoo2を定義するのは非常に苦痛です。 foo2のコンストラクターの最初の行をself.a = bar2()に置き換える必要があるため、コンストラクター全体を書き換えることを意味します。

4
Thomas

いいえ、構成はネストを意味しません。外側のクラスの名前空間でさらにクラスを非表示にする場合は、ネストされたクラスを使用するのが理にかなっています。

とにかく、私はあなたの場合のネストの実用的な使用を見ていません。コードが読みにくくなる(理解する)だけでなく、インデントが増えて行が短くなり、分割されやすくなります。

1