2

I'm using a singleton for a python class like the following example

class GestionnaireUtilisateur(object):
    __singleton = None

    def __new__(cls, *args, **kwargs):
        if not cls.__singleton:
            cls.__singleton = super(GestionnaireUtilisateur, cls).__new__(cls, *args, **kwargs)
        return cls.__singleton

    def __init__(self):
        self.compte = None

I can modifie self.__compte with the following method

def connexion(self, compte):
    self.compte = compte

On my first object GestionnaireUtilisateur(), I call the method connexion('toto') to modifie self.compte and the result is good. But when I call an another time the GestionnaireUtilisateur(), the self.compte is at None and not at the value I'm passing by connexion().

I make a test to not if the object are the same and they are. I have this result

<securecloud.utilisateur.gstutilisateur.GestionnaireUtilisateur object at 0xb73aad4c>
toto
<securecloud.utilisateur.gstutilisateur.GestionnaireUtilisateur object at 0xb73aad4c>
None

Someone have an idee?

Liberitus
  • 115
  • 1
  • 7

4 Answers4

2

When __new__ returns an instance of the class, the __init__ function is called on it. So you are reusing the same object, but calling __init__ on it each time.

It's better to do without complicated things like __new__. Instead of trying to implement a singleton like this, just use a factory function to create and return one object.

Forced singletons like this are often a bad idea anyway, testing becomes more complicated, and it's essentially a global value, which leads to unwanted coupling.

Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
0

You can check in the __init__ function if compte is present, to prevent overriding of the singleton attribute. But the second connection() will change the value of the first too.

class GestionnaireUtilisateur(object):
    __singleton = None

    def __new__(cls, *args, **kwargs):
        if not cls.__singleton:
            cls.__singleton = super(GestionnaireUtilisateur, cls).__new__(cls, *args, **kwargs)
        return cls.__singleton

    def connexion(self, compte):
        self.compte = compte

    def __init__(self):
        if not hasattr(self, "compte"):
            self.compte = None


s1 = GestionnaireUtilisateur()
print "'compte' before", s1.compte
s1.connexion('s1')
print "'compte' after", s1.compte

s2 = GestionnaireUtilisateur()
print "'compte' before", s2.compte
s2.connexion('s2')
print "'compte' after", s2.compte

print "s1 'compte' after", s1.compte

produces:

====================
instance s1
====================
'compte' before None
'compte' after s1
====================
instance s2
====================
'compte' before s1

'compte' after s2
s1 'compte' after s2
Tisho
  • 8,320
  • 6
  • 44
  • 52
0
class GestionnaireUtilisateur(object):
    __singleton = None

    def __new__(cls, *args, **kwargs):
        if not cls.__singleton:
            cls.__singleton = super(GestionnaireUtilisateur,
                cls).__new__(cls, *args, **kwargs)
            cls.__singleton._init()
        return cls.__singleton

    def __init__(self):
        print "Every time"

    def _init(self): # not __init__
        self.compte = None
        print "Once"
0

As @Ned said, singletons are generally not the right answer. You get much more flexibility by using the factory pattern, which is basically trivial in Python. However, if you really need to share state, perhaps think about using the Borg pattern instead.

class Borg(object):
    __shared_state = {}

    def __init__(self):
        self.__dict__ = __shared_state
voithos
  • 68,482
  • 12
  • 101
  • 116