- 1.1. Abstract Factory Pattern
- 1.2. Builder Pattern
- 1.3. Factory Method Pattern
- 1.4. Prototype Pattern
- 1.5. Singleton Pattern
1.5. Singleton Pattern
The Singleton Pattern is used when we need a class that has only a single instance that is the one and only instance accessed throughout the program.
For some object-oriented languages, creating a singleton can be surprisingly tricky, but this isn’t the case for Python. The Python Cookbook (code.active-state.com/recipes/langs/python/) provides an easy-to-use Singleton class that any class can inherit to become a singleton—and a Borg class that achieves the same end in a rather different way.
However, the easiest way to achieve singleton functionality in Python is to create a module with the global state that’s needed kept in private variables and access provided by public functions. For example, in Chapter 7’s currency example ( 237), we need a function that will return a dictionary of currency rates (name keys, conversion rate values). We may want to call the function several times, but in most cases we want the rates fetched only once. We can achieve this by using the Singleton Pattern.
_URL ="http://www.bankofcanada.ca/stats/assets/csv/fx-seven-day.csv"
def get(refresh=False): if refresh: get.rates = {} if get.rates: return get.rates with urllib.request.urlopen(_URL) as file: for line in file: line = line.rstrip().decode("utf-8"
) if not line or line.startswith(("#"
,"Date"
)): continue name, currency, *rest = re.split(r"\s*,\s*"
, line) key ="{} ({})"
.format(name, currency) try: get.rates[key] = float(rest[-1
]) except ValueError as err: print("error {}: {}"
.format(err, line)) return get.rates get.rates = {}
This is the code for the currency/Rates.py module (as usual, excluding the imports). Here, we create a rates dictionary as an attribute of the Rates.get() function—this is our private value. When the public get() function is called for the first time (or if it is called with refresh=True), we download the rates afresh; otherwise, we simply return the rates we most recently downloaded. There is no need for a class, yet we have still got a singleton data value—the rates—and we could easily add more singleton values.
All of the creational design patterns are straightforward to implement in Python. The Singleton Pattern can be implemented directly by using a module, and the Prototype Pattern is redundant (although still doable using the copy module), since Python provides dynamic access to class objects. The most useful creational design patterns for Python are the Factory and Builder Patterns; these can be implemented in a number of ways. Once we have created basic objects, we often need to create more complex objects by composing or adapting other objects. We’ll look at how this is done in the next chapter.