Gibt es einen Vorteil beim Definieren einer Klasse in einer anderen Klasse in Python?

106

Ich spreche hier von verschachtelten Klassen. Im Wesentlichen habe ich zwei Klassen, die ich modelliere. Eine DownloadManager-Klasse und eine DownloadThread-Klasse. Das offensichtliche OOP-Konzept ist hier die Komposition. Komposition bedeutet jedoch nicht unbedingt Verschachtelung, oder?

Ich habe Code, der ungefähr so ​​aussieht:

class DownloadThread:
    def foo(self):
        pass

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

Aber jetzt frage ich mich, ob es eine Situation gibt, in der das Verschachteln besser wäre. Etwas wie:

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

Antworten:

121

Möglicherweise möchten Sie dies tun, wenn die "innere" Klasse einmalig ist und niemals außerhalb der Definition der äußeren Klasse verwendet wird. Zum Beispiel ist es manchmal praktisch, eine Metaklasse zu verwenden

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

anstatt eine Metaklasse separat zu definieren, wenn Sie sie nur einmal verwenden.

Das einzige Mal, dass ich solche verschachtelten Klassen verwendet habe, habe ich die äußere Klasse nur als Namespace verwendet, um eine Reihe eng verwandter Klassen zusammenzufassen:

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

    class cls2(object):
       ...

Dann können Sie aus einem anderen Modul Group importieren und diese als Group.cls1, Group.cls2 usw. bezeichnen. Man könnte jedoch argumentieren, dass Sie mit einem Modul genau dasselbe (möglicherweise weniger verwirrend) erreichen können.

dF.
quelle
13
Ich würde argumentieren, dass Sie im zweiten Fall definitiv besser mit einem Modul oder Paket bedient werden sollten, das als Namespaces konzipiert ist.
Matthew Trevor
5
Dies ist eine fantastische Antwort. Einfach, auf den Punkt und erwähnt die alternative Methode der Verwendung von Modulen. +1
CornSmith
5
Nur zur Veranschaulichung: Für diejenigen, die sich hartnäckig weigern oder ihren Code nicht in einem hierarchischen Paket und geeigneten Modulen organisieren können, ist es manchmal besser, Klassen als Namespace zu verwenden, als nichts zu verwenden.
Acumenus
19

Ich kenne Python nicht, aber Ihre Frage scheint sehr allgemein zu sein. Ignoriere mich, wenn es spezifisch für Python ist.

Beim Verschachteln von Klassen dreht sich alles um den Umfang. Wenn Sie der Meinung sind, dass eine Klasse nur im Kontext einer anderen sinnvoll ist, ist die erstere wahrscheinlich ein guter Kandidat, um eine verschachtelte Klasse zu werden.

Es ist ein gängiges Muster, Hilfsklassen zu privaten, verschachtelten Klassen zu machen.

André Chalella
quelle
9
Nur zur Veranschaulichung: Das Konzept der privateKlassen gilt in Python nicht so häufig, aber ein impliziter Verwendungsbereich gilt definitiv.
Acumenus
Warum beantwortest du Python-bezogene Fragen mit I do not know python ...?
Awaaaaarghhh vor
7

Es gibt eine andere Verwendung für verschachtelte Klassen, wenn geerbte Klassen erstellt werden sollen, deren erweiterte Funktionen in einer bestimmten verschachtelten Klasse gekapselt sind.

Siehe dieses Beispiel:

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)

Beachten Sie, dass im Konstruktor von foodie Linie self.a = self.bar()a erstellt, foo.barwenn das zu erstellende Objekt tatsächlich ein fooObjekt ist, und ein foo2.barObjekt, wenn das zu erstellende Objekt tatsächlich ein foo2Objekt ist.

Wenn die Klasse baraußerhalb der Klasse definiert wurde foostattdessen sowie seine geerbten Version (die aufgerufen wird , würde bar2zum Beispiel), dann die neue Klasse zu definieren foo2wäre viel schmerzhafter, weil der Konstruktor von foo2müßte seine erste Linie ersetzt hat self.a = bar2(), Dies bedeutet, dass der gesamte Konstruktor neu geschrieben wird.

Thomas
quelle
6

Dies hat wirklich keinen Vorteil, es sei denn, Sie haben es mit Metaklassen zu tun.

Die Klasse: Suite ist wirklich nicht das, was Sie denken. Es ist ein seltsamer Bereich, und es macht seltsame Dinge. Es macht wirklich nicht einmal eine Klasse! Es ist nur eine Möglichkeit, einige Variablen zu sammeln - den Namen der Klasse, die Basen, ein kleines Wörterbuch mit Attributen und eine Metaklasse.

Der Name, das Wörterbuch und die Basen werden alle an die Funktion übergeben, die die Metaklasse ist, und dann wird sie der Variablen 'name' in dem Bereich zugewiesen, in dem sich die class: suite befand.

Was Sie durch das Durcheinander mit Metaklassen und durch das Verschachteln von Klassen in Ihren Standardklassen erreichen können, ist schwerer zu lesender Code, schwerer zu verstehender Code und seltsame Fehler, die furchtbar schwer zu verstehen sind, ohne genau zu wissen, warum die 'Klasse' Der Gültigkeitsbereich unterscheidet sich grundlegend von allen anderen Python-Gültigkeitsbereichen.

Jerub
quelle
3
Nicht einverstanden: Das Verschachteln von Ausnahmeklassen ist sehr nützlich, da Benutzer Ihrer Klasse nach Ihren benutzerdefinierten Ausnahmen suchen können, ohne unordentliche Importe durchführen zu müssen. ZBexcept myInstanceObj.CustomError, e:
RobM
2
@ Jerub, warum ist das so schlimm?
Robert Siemer
5

Sie könnten eine Klasse als Klassengenerator verwenden. Wie (in einigen aus dem Manschettencode :)

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'''

Ich denke, wenn Sie diese Funktionalität benötigen, wird es Ihnen sehr klar sein. Wenn Sie nichts Ähnliches tun müssen, ist dies wahrscheinlich kein guter Anwendungsfall.

tim.tadh
quelle
1

Nein, Komposition bedeutet nicht Verschachtelung. Es wäre sinnvoll, eine verschachtelte Klasse zu haben, wenn Sie sie mehr im Namespace der äußeren Klasse ausblenden möchten.

Jedenfalls sehe ich in Ihrem Fall keinen praktischen Nutzen für das Verschachteln. Dies würde das Lesen (Verstehen) des Codes erschweren und die Einrückung erhöhen, wodurch die Zeilen kürzer und anfälliger für das Teilen würden.

Cristian Ciupitu
quelle