No, not even close. If it were the same, when you execute obj2.getConteudo()
the message to be displayed should be "the world", not the default, because you changed the value of this attribute through obj
when done obj.write("ola mundo")
. If they were singleton , objects should, necessarily , share exactly the same state.
Both instances did not share the state because instance
is an immutable type (save this term, it will be important later). Even if it is defined as a class attribute, it will be distinguished among all instances of the same class when it is modified. Therefore, when creating the second instance, self.instance
will be null again, regardless of whether or not previous instances were created.
The simplest way to work around this problem would be to use a changeable type as a class attribute, such as a list or dictionary. For example:
class TestSingleton:
state = {
'instance': None
}
msg = "variável interna com dados padrão"
def getInstance(self):
if self.state['instance'] is None:
self.state['instance'] = TestSingleton()
return self.state['instance']
def getConteudo(self):
print(self.msg)
def write(self, mensagem):
self.msg = mensagem
So when you run the code:
obj = TestSingleton().getInstance()
obj.write("ola mundo")
obj.getConteudo() # ola mundo
obj2 = TestSingleton().getInstance()
obj2.getConteudo() # ola mundo
obj2.write("Que coisa !")
obj2.getConteudo() # Que coisa !
obj.getConteudo() # Que coisa !
That is, objects will share the state because they will be exactly the same instance.
Still, this solution would be bad, because in this way there would be three distinct instances, two of which will be used only to return the third. Imagine that you control flights at an airport is making people board on an airplane; it will only be one flight, but you are required to place two other aircraft to serve as a "corridor" for passengers to access the aircraft that will be used on the trip. Can you visualize the cost of it all?
To demonstrate this, it would be enough to separate the instance and execution operations from the getInstance
method, by doing:
obj1 = TestSingleton() # Aqui, obj1 seria a instância A
obj1 = obj1.getInstance() # E aqui, obj1 receberia a instância C
obj2 = TestSingleton() # Aqui, obj2 seria a instância B
obj2 = obj1.getInstance() # E aqui, obj2 receberia a instância C
At this point, starting the path to the ideal solution, you need to answer a question: Do I really need only one object, class instance, or can I have multiple objects sharing state? p>
In case you can share the state with multiple distinct objects, simply use a class attribute with type changeable, similar to what was done above using the dictionary. For example:
class Foo:
shared = {
'message': 'Olá mundo'
}
def getMessage(self):
return self.shared['message']
def setMessage(self, message):
self.shared['message'] = message
So you could do something like:
a = Foo()
print(a.getMessage()) # Olá mundo
a.setMessage('Nova mensagem')
b = Foo()
print(b.getMessage()) # Nova mensagem
print('São o mesmo objeto:', b is a) # São o mesmo objeto: False
The two objects will share the state defined in shared
, so that when the message is changed in a
, the change is reflected in b
.
Now, if you need to always be the same object (do not just share the state), you can create a base class by setting the constructor method __new__
:
class Singleton:
__instance = None
def __new__(cls, *args, **kwargs):
if Singleton.__instance is None:
Singleton.__instance = super().__new__(cls)
return Singleton.__instance
And so, you use inheritance in your class:
class Foo(Singleton):
def __init__(self, name):
self.name = name
For example:
a = Foo("Anderson")
print(a.name) # Anderson
b = Foo("Woss")
print(b.name) # Woss
print(a.name) # Woss
print('São o mesmo objeto:', b is a) # São o mesmo objeto: True
Notice that by setting b
to a different value, the name
attribute of a
is also changed as it will be the same object.