Your second option is a fine way to go -- it's a kind of dependency injection, which is the pattern used to share state across your program when you want to avoid singletons and global variables.
You can't get around the fact that something has to create your factory. If that something happens to be the application, so be it. The important point is that your factory shouldn't care what object created it, and the objects that receive the factory shouldn't depend on where the factory came from. Don't have your objects get a pointer to the application singleton and ask it for the factory; have your application create the factory and give it to those objects that will need it.
There are two problems come together here:
- Your package is a singleton although there exist many different configurations.
- Where to store the data and how to migrate - which database to use.
Singleton
I did a fun project with lots of modules which needed configuration themselves. The project was intended to run once per computer.
The alternative is to put everything into classes and instantiate them with a configuration. Tist would allow many different configurations to exist within one program. When you may have this need you should restructure your whole code.
Database
Maybe your project is for a company and shall be developed for a longer time and the configuration shall not be thrown away. Then you may need to keep in mind many previous configurations when changing the default values and updating the configuration. Proper databases have solved that problem.
My tradeoff solution
In my case
- The configuration can be thrown away if my model changes.
- The package runs not only once per process but also once per computer.
- Only one thread accesses the configuration.
There is a module called config.py with the following methods:
import config
config.load()
config.save()
You use it like this (Example1):
config.load()
config.my_value = 'test'
config.save()
There is also a file called constants.py which should better be called default_config.py
. It has the functions
import constants
constants.default_configuration()
constants.config_file_name() # where to store the config data
And for (Example1) the constants.py should look like this:
def default_configuration():
return {'my_value' : 'default'} # to avoid attribute errors
The config module saves and loads the configuration using pickle. If no configuration is found for a variable the default configuration is used.
You will need a coding style that always fetches the configuration from the config.py. It shall not be stored in a local variable or attribute over a longer time since it can change.
My previous version is called runningConfiguration. It has no explicit load and save and also no default attributes.
Best Answer
What is a singleton?
A singleton is an object of which there is only one, semantically, in memory.
Builtin singletons
None
is a frequently used singleton.NotImplemented
is another, much less used. We can test for singleton identity:And then
returns
True
.Creating a semantic singleton
You can just use an object instance to create one that needs no functionality in a module's global namespace (all caps, because it's a global constant):
Be careful not to overwrite the object on the global namespace. If you give it a good name, it should be obvious when someone is doing something wrong with it.
This is similar to the example you gave. However, I wouldn't do what you're doing if creating the object is expensive - it makes it so that it's expensive to import the module, even if you don't want to use the object.
Why you wouldn't want a global singleton on import
Where you would not want it to have a singleton created on import would be any time you want to inexpensively import the module.
You want your modules to be inexpensive to import when dynamically generating documentation, for example.
Another case where you should prefer inexpensive imports are for running unittests.
Also, the method you use does not support inheritance.
So I'm going to show you some ways to work around this.
A singleton instance
Where you only want to have one instance of a class, you can do this in various ways:
customize
__new__
and use a class attribute,instance
And note that this supports inheritance.
memoize a factory function
You can create a function attribute to memoize the function
You could also use the module or class namespace to keep the instance in - since the function and the module should both be singletons as well.
Or use lru_cache (since get_controller takes no arguments) to memoize it.
Note that if you add arguments to
get_controller
, lru_cache will return a singleton for each unique combination of arguments, up to its cache size (theoretically), after which it forgets instances, so be careful with this if you add arguments - probably better to implement your own behavior, as I did with the function attribute example.This can support inheritance, for example.