2017-02-14 10 views
2

Ich erstelle eine Python-Anwendung, die Socket-Kommunikation mit einem Server enthält. Ich würde gerne ein Modul haben, das während meiner gesamten Anwendung (mehrere andere Module) verwendet werden kann. Derzeit sehen mein Modul wie folgt aus:Einzelne Instanz der Klasse in Python

class SocketCommunication: 

    def __init__(self): 
     self.socketIO = SocketIO(settings.ADDRESS, settings.PORT, Namespace) 

    def emit(self, message, data): 
     json_data = json.dumps(data.__dict__) 
     self.socketIO.emit(message, json_data) 


class Namespace(BaseNamespace): 
    def on_connect(self): 
     print '[Connected]' 

    def on_disconnect(self): 
     print "[Disconnected]" 

Wenn ich diese Verwendung in anderen Modulen ich folgendes:

import SocketCommunication 
self.sc = SocketCommunication() 

Das Problem ist, dass jedes Mal, wenn ich dies tun, eine neue Verbindung erstellt wird, das wird Als neuer Client auf dem Server angezeigt werden, was unerwünscht ist. Von dem, was ich lesen kann, sollten Singletons in Python vermieden werden und daher bin ich neugierig, was ist die beste Praxis für diese Art von Problem?

+2

Lesen Sie über die ** _ The Borg Entwurfsmuster _ ** [hier] (http://code.activestate.com/recipes/577870-singleton-we-dont-need-no-stinkin-singleton-the-bo/) und [hier] (http://code.activestate.com/recipes/66531/) für eine einfache Möglichkeit, eine Klasse in einen Singleton umzuwandeln. Es gibt auch andere Möglichkeiten. – martineau

+1

Ich würde die Klasse selbst als Singleton verwenden. Ich hatte nie Probleme mit diesem Ansatz. – Alfe

+0

Die 'import SocketCommunication', die Sie in den anderen Modulen ausführen, würde nicht funktionieren, weil' SocketCommunication' der Name einer Ihrer Klassen ist. Es müsste etwas wie 'from my_module import SocketCommunication' sein, damit die nächste Zeile gültig ist. Das heißt, Sie könnten die Klasse effektiv zu einem Singleton machen, der 'SocketCommunication = SocketCommunication()' in 'my_module.py' hinzufügt, nachdem die Klasse definiert wurde. Auf diese Weise wird es sehr schwierig, weitere Instanzen zu erstellen, da der Klassenname mit einer Instanz von sich überschrieben werden muss. – martineau

Antwort

1

Es gibt drei Möglichkeiten, Singleton in Python zu verwenden. Verwenden Sie metaclass und decorator, um das Ziel zu erreichen.

  1. Verwendung __new__

    class Singleton(object): 
        def __new__(cls, *args, **kw): 
         if not hasattr(cls, '_instance'): 
          orig = super(Singleton, cls) 
          cls._instance = orig.__new__(cls, *args, **kw) 
         return cls._instance 
    
    class MyClass(Singleton): 
        a = 1 
    
    one = MyClass() 
    two = MyClass() 
    
    two.a = 3 
    print one.a 
    #3 
    print id(one) 
    #29097904 
    print id(two) 
    #29097904 
    print one == two 
    #True 
    print one is two 
    #True 
    
  2. Verwendung __metaclass__

    class Singleton2(type): 
        def __init__(cls, name, bases, dict): 
         super(Singleton2, cls).__init__(name, bases, dict) 
         cls._instance = None 
    
    def __call__(cls, *args, **kw): 
        if cls._instance is None: 
         cls._instance = super(Singleton2, cls).__call__(*args, **kw) 
        return cls._instance 
    
    
    class MyClass2(object): 
        __metaclass__ = Singleton2 
    
    one = MyClass2() 
    two = MyClass2() 
    
    two.a = 3 
    print one.a 
    #3 
    print id(one) 
    #31495472 
    print id(two) 
    #31495472 
    print one == two 
    #True 
    print one is two 
    #True 
    
  3. Verwendung decorator

    def singleton(cls, *args, **kw): 
        instances = {} 
        def _singleton(): 
         if cls not in instances: 
          instances[cls] = cls(*args, **kw) 
         return instances[cls] 
        return _singleton 
    
    @singleton 
    class MyClass3(object): 
        a = 1 
        def __init__(self, x=0): 
         self.x = x 
    
    one = MyClass3() 
    two = MyClass3() 
    
    two.a = 3 
    print one.a 
    #3 
    print id(one) 
    #29660784 
    print id(two) 
    #29660784 
    print one == two 
    #True 
    print one is two 
    #True 
    one.x = 1 
    print one.x 
    #1 
    print two.x 
    #1 
    

Ich bevorzuge die Verwendung decorator.

0

Singletons sind umstritten, weil sie oft als eine Möglichkeit zum Einschließen globaler Variablen verwendet werden. Aus diesem Grund befürworten einige Menschen ihre Vermeidung. Globals machen Tests schwieriger, sie beschränken die Zugriffskontrolle und führen oft zu starker Kopplung zwischen Variablen. (Siehe http://wiki.c2.com/?GlobalVariablesAreBad, um weitere Informationen darüber, warum Globals sind in der Regel schlechte Praxis)

In Ihrem speziellen Szenario mit einem Singleton ist am wahrscheinlichsten angemessen, weil Sie versuchen einfach, SocketCommunication zu stoppen mehrmals initialisiert werden (aus gutem Grund), eher als zu versuchen, es als Container für einen globalen Staat zu verwenden.

Weitere Informationen zu Singletons finden Sie unter Are Singletons really that bad? und What is so bad about singletons?.

+0

Danke für Ihre Antwort.Es scheint, dass in diesem speziellen Fall ein Singleton die beste Lösung ist, wenn ich nur eine einzelne Instanz der Klasse brauche. – user3170354

Verwandte Themen