Reputation: 3163
I have some few classes which are widespread in my Python application and which should have only one global instance (eg Logger, DbConnection). Python does not support static variables/methods in a class, so the usual Java/C++ way to create a singleton here does not work. I have looked for alternatives to implement singleton in Python. I want a simple (no metaprogramming if possible) and clean implementation. This looks good:
class MyClass(object):
def a():
pass
singleton = MyClass()
Using the singleton would be simple as
import myClass
myClass.singleton.a()
The direct assignment could be replaced by a creation function if object initialization is not so simple.
I could also create a getInstance() in module scope and always use it to get myObj.
Question 1) This works ok? The module code (myObj assignment) only runs the first time it is imported into some other module and myObj won't be created every time I import this module somewhere?
An alternative method I have seen is to use a globals module. Something like:
from myClass1 import MyClass1
from myClass2 import MyClass2
myObj1 = MyClass1()
myObj2 = MyClass2()
Using this:
import globals
globals.myObj1.a()
I tend to prefer the first alternative.
Question 2) Between the 2 solutions, what do you recommend?
Question 3) A third solution would be passing the widespread objects such as Logger to several classes/functions, but this is not a good solution imho. Is there a better solution not mentioned here ?
I'm aware of the downsides of using global variables and singletons. However, having a global state is not a big issue in my application. I'll prefer solutions that have code clarity and are simple to use.
Upvotes: 6
Views: 4642
Reputation: 1985
Consider creating the following:
The state class will create a thread that will be initialized in an init.py module. The state class will have methods that pass class instances into the thread and save a weakref to it.
Later, a proxy class can be used to access the class instances in the thread. If the class objects are not created, then the proxy will create an instance of the desired class and save it to the thread.
Using this pattern, you could restrict the number of instances of each class to 1, and ensure that whenever an part of your application is running, any instance that needs to be used globally, repeatedly, would not have to be recreated.
Upvotes: 0
Reputation: 18848
If you want to have a logger
class that only has one instance, just make it a separate module.
# In logging.py
def log(msg):
print msg
Then from any script you want logging in.
from logging import log
log("A critical error occured.")
Upvotes: 5
Reputation: 39451
The correct answer to how to make singletons? Don't. You should explicitly pass a reference to everything which needs to use it. You can reduce the effort with factory functions, wrapper classes and the like.
Even if there is something, like the screen or logger which is global in nature, you should still pass it explicitly to allow for unit testing. Note that this only applies to things intended to be part of the final design. If your logger is just a quick hack for debugging, feel free to make it global.
Upvotes: 0