554 Stimmen

Gibt es eine einfache, elegante Möglichkeit, Singletons zu definieren?

Es scheint viele Möglichkeiten der Definition zu geben Einzelnes in Python. Gibt es eine einheitliche Meinung auf Stack Overflow?

51voto

Wei Punkte 505

Siehe diese Implementierung von PEP318 und implementiert das Singleton-Muster mit einem Dekorator:

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
    ...

49voto

Brian Bruggeman Punkte 4476

Le site Python-Dokumentation deckt dies ab:

class Singleton(object):
    def __new__(cls, *args, **kwds):
        it = cls.__dict__.get("__it__")
        if it is not None:
            return it
        cls.__it__ = it = object.__new__(cls)
        it.init(*args, **kwds)
        return it
    def init(self, *args, **kwds):
        pass

Ich würde es wahrscheinlich so umschreiben, dass es mehr wie folgt aussieht:

class Singleton(object):
    """Use to create a singleton"""
    def __new__(cls, *args, **kwds):
        """
        >>> s = Singleton()
        >>> p = Singleton()
        >>> id(s) == id(p)
        True
        """
        it_id = "__it__"
        # getattr will dip into base classes, so __dict__ must be used
        it = cls.__dict__.get(it_id, None)
        if it is not None:
            return it
        it = object.__new__(cls)
        setattr(cls, it_id, it)
        it.init(*args, **kwds)
        return it

    def init(self, *args, **kwds):
        pass

class A(Singleton):
    pass

class B(Singleton):
    pass

class C(A):
    pass

assert A() is A()
assert B() is B()
assert C() is C()
assert A() is not B()
assert C() is not B()
assert C() is not A()

Es sollte relativ einfach sein, dies zu erweitern:

class Bus(Singleton):
    def init(self, label=None, *args, **kwds):
        self.label = label
        self.channels = [Channel("system"), Channel("app")]
        ...

31voto

u0b34a0f6ae Punkte 45029

Ich bin mir da sehr unsicher, aber mein Projekt verwendet "Konventionssingletons" (nicht erzwungene Singletons), das heißt, wenn ich eine Klasse namens DataController Ich definiere dies in demselben Modul:

_data_controller = None
def GetDataController():
    global _data_controller
    if _data_controller is None:
        _data_controller = DataController()
    return _data_controller

Er ist nicht elegant, da er ganze sechs Zeilen lang ist. Aber alle meine Singletons verwenden dieses Muster, und es ist zumindest sehr explizit (was pythonisch ist).

30voto

Lambda Fairy Punkte 12538

Da die akzeptierte Antwort sagt, dass die idiomatischste Art und Weise darin besteht, einfach ein Modul verwenden .

In diesem Sinne, hier ist ein Beweis für das Konzept:

def singleton(cls):
    obj = cls()
    # Always return the same object
    cls.__new__ = staticmethod(lambda cls: obj)
    # Disable __init__
    try:
        del cls.__init__
    except AttributeError:
        pass
    return cls

Siehe die Python-Datenmodell für weitere Informationen über __new__ .

Beispiel:

@singleton
class Duck(object):
    pass

if Duck() is Duck():
    print "It works!"
else:
    print "It doesn't work!"

Notas:

  1. Sie müssen New-Style-Klassen verwenden (Ableitung von object ) für diese.

  2. Das Singleton wird initialisiert, wenn es definiert wird, und nicht bei der ersten Verwendung.

  3. Dies ist nur ein Beispiel für ein Spielzeug. Ich habe nie tatsächlich verwendet diese in der Produktion Code, und nicht planen, zu.

18voto

David Locke Punkte 17314

Das eine Mal, als ich ein Singleton in Python geschrieben habe, habe ich eine Klasse verwendet, in der alle Mitgliedsfunktionen den classmethod-Dekorator hatten.

class Foo:
    x = 1

    @classmethod
    def increment(cls, y=1):
        cls.x += y

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X