It appears that you have not understood how to use the singleton
decorator. You are working under the mistaken assumption that the class you decorate with singleton
becomes an attribute of singleton
. It does not.
Here is an example of how it works. Note that I have slightly modified the definition of singleton
to remove some cruft. It only works in Python 3. If you need to use this decorator in Python 3, some of the cruft will have to be put back.
from functools import wraps
def singleton(cls):
instance = None
@wraps(cls)
def getinstance(*args, **kwds):
nonlocal instance
if instance is None:
instance = cls(*args, **kwds)
return instance
return getinstance
# Check that it works ... first use the decorator on a class definition
@singleton
class Foo:
pass
# Now instantiate the class twice ...
a = Foo()
b = Foo()
# ... and verify that we have only one instance.
assert a is b
Python's is
operator verifies object identity. the assert a is b
confirms that a
and b
are the same single instance.
Here is how verify that it works in a way which resembles a bit more what you tried to do in your test code:
# Showing how it works with your example
@singleton
class OTConn:
# Your class variable `conn` and constructor were completely
# irrelevant, so I leave them out
pass
ot_conn_a = OTConn()
ot_conn_a.conn = 'a'
ot_conn_b = OTConn()
assert ot_conn_b.conn == 'a'
The most important difference between your code and mine, is that singleton.OTConn
does not appear anywhere in mine. It cannot possbily work! (Unless there is some code which you haven't shown us, which makes it work.)
Step-by-step instrctions how to observe singleton
functioning correctly
The behaviour you report, and your continued refusal to describe exactly how it is that you think you are executing this code in a single process, gives the very strong impression that you are executing this in separate processes. As has been pointed out to you by many people, your singleton class cannot possibly work in that case.
Here I give you a step-by-step recipe how to observe singleton
working correctly in multiple modules but a single process.
Step 1: create a directory (folder) in which you will create the following python source files.
Step 2: In the directory you created in step 1 create a file called singleton.py
containing the following code:
def singleton(cls):
instance = None
@wraps(cls)
def getinstance(*args, **kwds):
nonlocal instance
if instance is None:
instance = cls(*args, **kwds)
return instance
return getinstance
Step 3: In the same directory create a file called theclass.py
containing the code
from singleton import singleton
@singleton
class TheClass:
def __init__(self):
self.conn = None
Step 4: Again, in the same directory create a file called client1.py
containing
from theclass import TheClass
instance = TheClass()
print("In client1.py instance.conn =", instance.conn)
instance.conn = 'XXXX'
print("In client1.py instance.conn =", instance.conn)
Step 5: ... and also a file called client2.py
containing
from theclass import TheClass
instance = TheClass()
print("In client2.py instance.conn =", instance.conn)
Step 6: The last file you need should be called main.py
and contain
from client1 import instance as i1
from client2 import instance as i2
print("In main.py i1.conn =", i1.conn)
print("In main.py i2.conn =", i2.conn)
i2.conn = 'YYY'
print("In main.py i1.conn =", i1.conn)
print("In main.py i2.conn =", i2.conn)
Step 7: Execute main.py
Step 8: observe the output
In client1.py instance.conn = None
In client1.py instance.conn = XXXX
In client2.py instance.conn = XXXX
In main.py i1.conn = XXXX
In main.py i2.conn = XXXX
In main.py i1.conn = YYY
In main.py i2.conn = YYY
As you can see from the output
TheClass
is instantiated in two separate modules.
- the
conn
attribute of the instances starts of as None
- Setting this attribute's value to
'XXXX'
sets it for both instances.
- Setting this attribute's value to
'YYY'
, this time using the other instance to do so, once again changes both instances.
The unavoidable conclusion is that singleton
works as advertised. But this does crucially rely on both instances being in the same process.