Domanda

A questa domanda ha già una risposta qui:

Sembra che ci siano molti modi per definire singleton in Python.C'è un consenso di opinione su Stack Overflow?

È stato utile?

Soluzione

Non vedo la necessità, come un modulo con funzioni (e non di una classe) dovrebbe servire anche come un singleton.Tutte le sue variabili è legato al modulo, che potrebbe non essere istanziato ripetutamente comunque.

Se si desidera utilizzare una classe, non c'è modo di creare lezioni private oppure i costruttori privati in Python, quindi non si può proteggere contro le diverse istanze, altro che solo tramite convenzione con l'utilizzo della API.Vorrei ancora mettere solo metodi in un modulo, e considerare il modulo come il singleton.

Altri suggerimenti

Questa è la mia implementazione di singoletti.Tutto quello che dovete fare è decorare la classe;per ottenere il singleton, è quindi necessario utilizzare il Instance metodo.Ecco un esempio:

@Singleton
class Foo:
   def __init__(self):
       print 'Foo created'

f = Foo() # Error, this isn't how you get the instance of a singleton

f = Foo.instance() # Good. Being explicit is in line with the Python Zen
g = Foo.instance() # Returns already created instance

print f is g # True

Ed ecco il codice:

class Singleton:
    """
    A non-thread-safe helper class to ease implementing singletons.
    This should be used as a decorator -- not a metaclass -- to the
    class that should be a singleton.

    The decorated class can define one `__init__` function that
    takes only the `self` argument. Also, the decorated class cannot be
    inherited from. Other than that, there are no restrictions that apply
    to the decorated class.

    To get the singleton instance, use the `instance` method. Trying
    to use `__call__` will result in a `TypeError` being raised.

    """

    def __init__(self, decorated):
        self._decorated = decorated

    def instance(self):
        """
        Returns the singleton instance. Upon its first call, it creates a
        new instance of the decorated class and calls its `__init__` method.
        On all subsequent calls, the already created instance is returned.

        """
        try:
            return self._instance
        except AttributeError:
            self._instance = self._decorated()
            return self._instance

    def __call__(self):
        raise TypeError('Singletons must be accessed through `instance()`.')

    def __instancecheck__(self, inst):
        return isinstance(inst, self._decorated)

È possibile ignorare il __new__ metodo come questo:

class Singleton(object):
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(
                                cls, *args, **kwargs)
        return cls._instance


if __name__ == '__main__':
    s1 = Singleton()
    s2 = Singleton()
    if (id(s1) == id(s2)):
        print "Same"
    else:
        print "Different"

Un approccio leggermente diverso per implementare il singleton in Python è il borg modello by Alex Martelli (dipendente di Google e Python genio).

class Borg:
    __shared_state = {}
    def __init__(self):
        self.__dict__ = self.__shared_state

Così, invece di costringere tutte le istanze per la stessa identità, condividono stato.

Il modulo di approccio funziona bene.Se ho assolutamente bisogno di un singleton io preferisco il Metaclass approccio.

class Singleton(type):
    def __init__(cls, name, bases, dict):
        super(Singleton, cls).__init__(name, bases, dict)
        cls.instance = None 

    def __call__(cls,*args,**kw):
        if cls.instance is None:
            cls.instance = super(Singleton, cls).__call__(*args, **kw)
        return cls.instance

class MyClass(object):
    __metaclass__ = Singleton

Vedere questa implementazione PEP318, implementando il singleton pattern con un decoratore:

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

@singleton
class MyClass:
    ...

Come accettato risposta dice, più idiomatiche modo è utilizzare un modulo.

Con questo in mente, ecco una prova di concetto:

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

Vedere la Python modello di dati per ulteriori dettagli su __new__.

Esempio:

@singleton
class Duck(object):
    pass

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

Note:

  1. È necessario utilizzare il nuovo stile di classi (derivano da object) per questo.

  2. Il singleton è inizializzato quando è definita, piuttosto che la prima volta che viene utilizzato.

  3. Questo è solo un giocattolo, per esempio.Non ho mai usato questo nel codice di produzione, e non hai intenzione di.

Sono molto dubbi su questo, ma il mio progetto si avvale di "convenzione singoletti' (non imposto singleton), che è, se ho una classe chiamata DataController, Definisco questo nel modulo stesso:

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

Non è elegante, dal momento che si tratta di un full di sei linee.Ma tutti i miei singoletti utilizzare questo modello, ed è almeno molto esplicito (che è divinatori).

Il Documentazione di Python non coprire questo:

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

Io probabilmente riscrivere per assomigliare di più a questo:

class Singleton(object):
    """Use to create a singleton"""
    def __new__(cls, *args, **kwds):
        """
        >>> s = Singleton()
        >>> p = Singleton()
        >>> id(s) == id(p)
        True
        """
        self = "__self__"
        if not hasattr(cls, self):
            instance = object.__new__(cls)
            instance.init(*args, **kwds)
            setattr(cls, self, instance)
        return getattr(cls, self)

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

Dovrebbe essere relativamente pulito per estendere questo:

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

L'unica volta che ho scritto un singleton in Python ho usato una classe dove tutti le funzioni membro aveva la classmethod decoratore.

class foo:
  x = 1

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

Ci sono anche alcuni interessanti articoli su Test Google blog, parlando del perché singleton sono/possono essere cattivi e sono un anti-pattern:

Creazione di un singleton decoratore (aka un'annotazione) è un modo elegante se volete decorare (annotazioni) classi di andare avanti.Poi basta mettere @singleton prima della definizione della classe.

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

@singleton
class MyClass:
    ...

Qui è un esempio da Peter Norvig Python IAQ Come faccio a fare il Singleton Pattern in Python? (Si consiglia di utilizzare la funzione di ricerca del browser per trovare a questa domanda, non esiste un collegamento diretto, sorry)

Anche Bruce Eckel è un altro esempio, nel suo libro Pensare in Python (di nuovo, non c'è nessun legame diretto con il codice)

Penso che costringendo una classe o di un'istanza per essere un singleton è eccessivo.Personalmente, mi piace definire un normale istanze di classe, un semi-privato di riferimento, e una semplice fabbrica di funzione.

class NothingSpecial:
    pass

_the_one_and_only = None

def TheOneAndOnly():
    global _the_one_and_only
    if not _the_one_and_only:
        _the_one_and_only = NothingSpecial()
    return _the_one_and_only

O se non c'è nessun problema con la creazione di un'istanza quando il modulo viene importato per la prima volta:

class NothingSpecial:
    pass

THE_ONE_AND_ONLY = NothingSpecial()

In questo modo si può scrivere test contro fresca istanze senza effetti collaterali, e non c'è bisogno per guarnire il modulo con affermazioni globali, e, se necessario, è possibile derivare varianti in futuro.

Il Singleton Pattern implementato con Python per gentile concessione di ActiveState.

Sembra che il trucco è quello di mettere la classe che dovrebbe avere solo un esempio all'interno di un'altra classe.

Essendo relativamente nuovo per Python non sono sicuro di quello che la maggior parte idioma comune, ma la cosa più semplice che posso pensare è solo utilizzo di un modulo invece di una classe.Quali sarebbero stati i metodi di istanza diventata la classe solo le funzioni del modulo e tutti i dati diventano variabili nel modulo invece di membri della classe.Ho il sospetto che questo è il divinatori approccio per risolvere il tipo di problema che la gente usa singleton per.

Se si vuole veramente una classe singleton, c'è una ragionevole attuazione descritto sul primo hit su Google per "Python singleton", in particolare:

class Singleton:
    __single = None
    def __init__( self ):
        if Singleton.__single:
            raise Singleton.__single
        Singleton.__single = self

Che sembra fare il trucco.

OK, singleton potrebbe essere il bene o il male, lo so.Questo è il mio attuazione, e ho semplicemente estendere un classico approccio per introdurre una cache interna e la produzione di istanze di un tipo diverso o, in molti casi dello stesso tipo, ma con parametri diversi.

Ho chiamato Singleton_group, perché i gruppi di simili istanze insieme e impedire che un oggetto della stessa classe, con gli stessi argomenti, potrebbe essere creato:

# Peppelinux's cached singleton
class Singleton_group(object):
    __instances_args_dict = {}
    def __new__(cls, *args, **kwargs):
        if not cls.__instances_args_dict.get((cls.__name__, args, str(kwargs))):
            cls.__instances_args_dict[(cls.__name__, args, str(kwargs))] = super(Singleton_group, cls).__new__(cls, *args, **kwargs)
        return cls.__instances_args_dict.get((cls.__name__, args, str(kwargs)))


# It's a dummy real world use example:
class test(Singleton_group):
    def __init__(self, salute):
        self.salute = salute

a = test('bye')
b = test('hi')
c = test('bye')
d = test('hi')
e = test('goodbye')
f = test('goodbye')

id(a)
3070148780L

id(b)
3070148908L

id(c)
3070148780L

b == d
True


b._Singleton_group__instances_args_dict

{('test', ('bye',), '{}'): <__main__.test object at 0xb6fec0ac>,
 ('test', ('goodbye',), '{}'): <__main__.test object at 0xb6fec32c>,
 ('test', ('hi',), '{}'): <__main__.test object at 0xb6fec12c>}

Ogni oggetto porta il singleton di cache...Questo potrebbe essere il male, ma funziona alla grande per un po :)

class Singleton(object[,...]):

    staticVar1 = None
    staticVar2 = None

    def __init__(self):
        if self.__class__.staticVar1==None :
            # create class instance variable for instantiation of class
            # assign class instance variable values to class static variables
        else:
            # assign class static variable values to class instance variables

La mia soluzione semplice che si basa sul valore di default dei parametri di funzionamento.

def getSystemContext(contextObjList=[]):
    if len( contextObjList ) == 0:
        contextObjList.append( Context() )
        pass
    return contextObjList[0]

class Context(object):
    # Anything you want here

Singleton, il fratello di mezzo

Sono completamente d'accordo con staale e lascio qui un esempio di creazione di un singleton fratello di mezzo:

class void:pass
a = void();
a.__class__ = Singleton

a sarà il racconto di una stessa classe come singleton, anche se non sembra.Così singoletti utilizzando complicato classi di finire secondo noi non si scherza molto con loro.

Stando così le cose, si può avere lo stesso effetto e usare cose più semplici come una variabile o di un modulo.Ancora, se vogliamo utilizzare le classi per chiarezza e perché in Python una classe è un oggetto, così abbiamo già oggetto (non di istanza, ma non farà proprio come).

class Singleton:
    def __new__(cls): raise AssertionError # Singletons can't have instances

Ci facciamo una bella affermazione di errore se si tenta di creare un'istanza, e siamo in grado di memorizzare su derivazioni membri statici e di apportare modifiche in fase di runtime (mi piace Python).Questo oggetto è buono come gli altri circa la metà fratelli (è ancora possibile creare loro se lo si desidera), ma tendono a correre più veloce grazie alla semplicità.

class Singeltone(type):
    instances = dict()

    def __call__(cls, *args, **kwargs):
        if cls.__name__ not in Singeltone.instances:            
            Singeltone.instances[cls.__name__] = type.__call__(cls, *args, **kwargs)
        return Singeltone.instances[cls.__name__]


class Test(object):
    __metaclass__ = Singeltone


inst0 = Test()
inst1 = Test()
print(id(inst1) == id(inst0))

Nei casi In cui non si desidera che il metaclass a base di soluzione di cui sopra, e non come la semplice funzione di decoratore-based approach (ad es.perché in quel caso i metodi statici sulla classe singleton che non funziona), questo compromesso opere:

class singleton(object):
  """Singleton decorator."""

  def __init__(self, cls):
      self.__dict__['cls'] = cls

  instances = {}

  def __call__(self):
      if self.cls not in self.instances:
          self.instances[self.cls] = self.cls()
      return self.instances[self.cls]

  def __getattr__(self, attr):
      return getattr(self.__dict__['cls'], attr)

  def __setattr__(self, attr, value):
      return setattr(self.__dict__['cls'], attr, value)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top