Python-Klassen mit nur einer Instanz: Wann wird eine (einzelne) Klasseninstanz erstellt und wann wird stattdessen mit der Klasse gearbeitet?

11

Bei einer Python-Klasse, die nur einmal instanziiert wird, gibt es nur ein Objekt der Klasse. Ich habe mich gefragt, in welchen Fällen es sinnvoll ist, eine einzelne Klasseninstanz zu erstellen, anstatt stattdessen direkt mit der Klasse zu arbeiten.

Es gibt eine ähnliche Frage , aber sie hat einen anderen Schwerpunkt:

  1. Es geht darum, globale Variablen und Funktionen in einer Klasse und zu gruppieren
  2. Es ist nicht Python-spezifisch. Letzteres bedeutet, dass die Tatsache, dass (in Python) Klassen ebenfalls Objekte sind, nicht berücksichtigt wird.

AKTUALISIEREN:

In Python kann ich sowohl mit Klassen als auch mit Objekten Folgendes tun:

class A(object):
    pass

A.some_state_var = True
# Then later
A.some_state_var = False


my_a = A()

my_a.some_state_var = True
# Then later
my_a.some_state_var = False

Ich sehe also nicht, wie es bei der Wahl zwischen einer Klasse und einer Instanz dieser Klasse um den Status geht (in Python). Ich kann mit beiden einen Zustand aufrechterhalten.

Darüber hinaus besteht die Motivation zum Erstellen meiner Klasse / Klasseninstanz nicht darin, eine Singleton-Anforderung durchzusetzen.

Außerdem geht es nicht so sehr darum, einen neuen Typ zu erstellen.

Die Motivation besteht darin, verwandten Code und Daten zu gruppieren und eine Schnittstelle dazu zu haben. Aus diesem Grund habe ich es zunächst als Klasse in einem Klassendiagramm modelliert. Erst als es um die Implementierung ging, fragte ich mich, ob ich diese Klasse instanziieren sollte oder nicht.

langlauf.io
quelle

Antworten:

16

Bei einer Python-Klasse, die nur einmal instanziiert wird, gibt es nur ein Objekt der Klasse. Ich habe mich gefragt, in welchen Fällen es sinnvoll ist, eine einzelne Klasseninstanz zu erstellen, anstatt stattdessen direkt mit der Klasse zu arbeiten.

Also ist es das:

class Singleton:
    '''don't bother instantiating me'''
    clsvar1 = 'foo'

    @classmethod
    def foobar(cls, *args, **kwargs):
        if condition():
            cls.clsvar1 = 'bar'

gegen das?

class Singleton:
    '''instantiate and use me'''
    def __init__(self):
        self.var1 = 'foo'

    def foobar(self, *args, **kwargs):
        if condition():
            self.var1 = 'bar'

Empfehlung

Ich würde definitiv diejenige bevorzugen, die instanziiert werden soll. Wenn Sie einen "Typ von Dingen" erstellen, bedeutet dies, dass Sie Dinge dieses Typs erstellen.

Die Motivation besteht darin, verwandten Code und Daten zu gruppieren und eine Schnittstelle dazu zu haben.

Das heißt, warum nicht einfach ein Modul verwenden, da alles, was Sie wollen, ein Namespace ist? Module sind Singletons, gruppenbezogener Code und Daten, und dies ist etwas einfacher und wird wahrscheinlich als pythonischer angesehen:

var1 ='foo'

def foobar(*args, **kwargs):
    global var1
    if condition():
        var1 = 'bar'

Die Verwendung wäre also anstelle von:

from modules.singleton import Singleton
Singleton.foobar()

oder

from modules.singleton import Singleton
the_singleton = Singleton()
the_singleton.foobar()

mach das:

from modules import singleton
singleton.foobar()
Aaron Hall
quelle
3
Danke für deine Antwort. Würden Sie wirklich vorschlagen, für jede Funktion (inkl. Variablen) ein neues Modul (eine neue .py-Datei) zu erstellen? Dies kann zu vielen kleinen .py-Dateien führen. Oder würden Sie alle (zumindest irgendwie verwandten) "klassenlosen" Funktionen und Variablen in einem Modul zusammenfassen?
langlauf.io
Noch eine Bemerkung: Sie schreiben "da Sie nur einen Namespace wollen". Ich möchte verwandten Code, dh Funktionen und Daten, an einem Ort gruppieren und eine Schnittstelle dazu haben. Es geht nicht so sehr darum, einen "Typ" zu erstellen. Während des Entwurfs würde dies sowieso zu einer Klasse in einem Klassendiagramm führen, nicht wahr?
langlauf.io
2

Ich habe mich gefragt, in welchen Fällen es sinnvoll ist, eine einzelne Klasseninstanz zu erstellen, anstatt stattdessen direkt mit der Klasse zu arbeiten.

Dies ist eines der Dinge, die einen Religionskrieg verursachen, wenn Sie sich zu sehr darauf einlassen.

Aber im Allgemeinen ist eine Praxis, die ich oft gesehen habe, dass Klassenmethoden sich nur mit dem Erstellen von Instanzen dieser Klasse befassen sollten.

Wenn Sie darüber nachdenken, was eine Klasse ist, was ihr Zweck / Verhalten ist, dann ist dies sinnvoll. Der Zweck einer Klasse besteht darin, Instanzen von Objekten zu erstellen, die auf sich selbst basieren . Es ist eine Blaupause, die auch das Gebäude bauen kann. Eine "Benutzer" -Klasse erstellt "Benutzer" -Objekte. Eine "Hund" -Klasse erstellt "Hund" -Objekte usw.

Wenn dies das Verhalten einer Klasse ist, ist es sinnvoll, dass Methoden, die Sie der Klasse "X" hinzufügen, sich mit dem Erstellen von "x" -Objekten befassen.

Selbst wenn Sie immer nur ein "x" -Objekt benötigen, sollten Sie es dennoch instanziieren.

Das Hinzufügen von Methoden zur X-Klasse, die nicht mit dem Erstellen von Instanzen von "x" -Objekten zusammenhängen, kann zu verwirrendem unerwartetem Code führen. Es gibt natürlich Unmengen von Beispielen in der realen Welt, in denen die Menschen dies sowieso getan haben, aber wie gesagt, dieser Weg führt zu einem Religionskrieg.

Cormac Mulhall
quelle