Create an account


Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tut] How to Create a Singleton in Python?

#1
How to Create a Singleton in Python?

Master coders behave like architects that connect and build upon various design patterns to create a functional whole. One of the most important design patterns is a singleton—a class that has only one instance. You may ask: How does that look like? Let’s have a look at the code implementing a singleton in our interactive code shell:

Exercise: Try to create multiple instances of the singleton class. Can you do it?

Let’s dive into a deeper understanding of the singleton. We’ll discuss this code in our first method, so keep reading!

What’s a Singleton?


A singleton is a class that has only one instance. All variables for the class point to the same instance. It is simple and straight forward to create and use and it is one of the design patterns described by the Gang of Four. After creating the first instance, all other creations point to the first instance created. It also solves the problem of having global access to a resource without using global variables. I like this concise definition from Head First Design Patterns:

The Singleton Pattern ensures a class has only one instance, and provides a global point of access to it.

Why Would You Need a Singleton?


If you are reading this, you likely already have a possible use. Singleton is one of the Gang of Four’s Creational patterns. Read on to determine if its a good candidate for the problem you need to solve.

A singleton can be used to access a common resource like a database or a file. There is a bit of controversy on its use. In fact, the controversy could be described as outright singleton shaming. If that concerns you, I’ve listed some of the objections below with some links. In spite of all that, singletons can be useful and pythonic. From The Zen of Python (Pythonistas say Ohm):

  • Simple is better than complex
  • Practicality beats purity

Still the objections have merit and may apply to the code you are currently working on. And even if they don’t apply, understanding those objections may give you a better understanding of Object Oriented principals and unit testing.

A singleton may be useful to control access to anything that changes globally when it is used. In addition to databases and files, a singleton may provide benefit for access to these resources:

  • Logger
  • Thread pools
  • caches
  • dialog boxes
  • An Http client
  • handles to preference settings
  • objects for logging
  • handles for device drivers like printers.
  • (?) Any single resource or global collection

A singleton can be used instead of using a global variable. Global variables are potentially messy. Singletons have some advantages over global variables. A singleton can be created with eager or lazy creation. Eager creation can create the resource when the program starts. Lazy creation will create the instance only when it is first needed. Global variables will use an eager creation whether you like it or not. Singletons do not pollute the global namespace.

And finally, a singleton can be a part of a larger design pattern. It may be part of any of the following patterns:

  • abstract factory pattern
  • builder pattern
  • prototype pattern
  • facade pattern
  • state objects pattern If you have not heard of these, no worries. It won’t affect your understanding of the singleton pattern.

Implementation


The standard C# and Java implementations rely on creating a class with a private constructor. Access to the object is given through a method: getInstance()

Here is a typical lazy singleton implementation in Java:

public Singleton { private static Singleton theOnlyInstance; private Singleton() {} public static Singleton getInstance() { if (theOnlyInstance) == null){ theOnlyInstance = new Singleton() } return new Singleton(); }
}

There are many ways to implement Singleton in Python. I will show all four first and discuss them below.

Method 1: Use __new__


class Singleton: _instance = None def __new__(cls): if cls._instance is None: cls._instance = super(Singleton, cls).__new__(cls) # Initialize here. No need to use __init__().. cls.val = 0 return cls._instance def business_method(self, val): self.val = val x = Singleton()
y = Singleton()
x.val = 42
x is y, y.val

It uses the Python dunder __new__ that was added to Python to provide an alternative object creation method. This is the kind of use case __new__ was designed for

Pros:

  • I believe this implementation is the closest in spirit to the GoF implementation. It will look familiar to anybody familiar with the standard Singleton implementation.
    • Easy to understand code meaning is important for teams and maintenance.
  • Uses one class to create and implement the Singleton.

Cons:

  • In spite of its ‘correctness’ many python coders will have to look up __new__ to understand the object creation specifics. Its enough to know that
    1. __new__ instantiates the object.
    2. Code that normally goes in __init__ can be placed in __new__.
    3. In order to work correctly the overridden __new__ must call its parent’s __new__ method. In this case, object is the parent. Instantiaion happens here with this line:
      • object.__new__(class_, *args, **kwargs)

Method 2: A Decorator


def singleton(Cls): singletons = {} def getinstance(*args, **kwargs): if Cls not in singletons: singletons[Cls] = Cls(*args, **kwargs) return singletons[Cls] return getinstance @singleton
class MyClass: def __init__(self): self.val = 3 x = MyClass()
y = MyClass()
x.val = 42
x is y, y.val, type(MyClass)

Pros

  • The code to write the decorator is separate from the class creation.
  • It can be reused to make as many singletons as you need.
  • The singleton decorator marks an intention that is clear and understandable

Cons

  • The call type(MyClass) will resolve as function.
    • Creating a class method in MyClass will result in a syntax error.

If you really want to use a decorator and must retain class definition, there is a way. You could use this library:

pip install singleton_decorator

The library singleton_decorator wraps and renames the singleton class. Alternately you can write your own. Here is an implementation:

def singleton(Cls): class Decorated(Cls): def __init__(self, *args, **kwargs): if hasattr(Cls, '__init__'): Cls.__init__(self, *args, **kwargs) def __repr__(self) : return Cls.__name__ + " obj" __str__ = __repr__ Decorated.__name__ = Cls.__name__ class ClassObject: def __init__(cls): cls.instance = None def __repr__(cls): return Cls.__name__ __str__ = __repr__ def __call__(cls, *args, **kwargs): if not cls.instance: cls.instance = Decorated(*args, **kwargs) return cls.instance return ClassObject() @singleton
class MyClass(): pass x = MyClass()
y = MyClass()
x.val = 42
x is y, y.val

The output is:

(True, 42)

Interactive Exercise: Run the following interactive memory visualization. How many singleton instances do you find?

Method 3: Use Metaclass and Inherit From Type and Override __call__ to Trigger or Filter Instance Creation


class Singleton(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instances[cls] class MyClass(metaclass=Singleton): pass x = MyClass()
y = MyClass()
x.val=4
x is y, y.val

The output is as follows:

(True, 4)

Method 3 creates a new custom metaclass by inheriting from type. MyClass then assigns Singleton as its metadata:

class MyClass(metadata = Singleton):

The mechanics of the Singleton class are interesting. It creates a dictionary to hold the instantiated singleton objects. The dict keys are the class names. In the overridden __call__ method, super.__call__ is called to create the class instance. See custom metaclass to better understand the __call__ method.

Pros

  • Singleton code is separate. Multiple singletons can be created using the same

Cons

  • Metaclasses remain mysterious for many python coders. Here is what you need to know:
    • In this implementation, type is inherited:
      • class Singleton(type)
    • In order to work correctly the overridden __call__ must call its parent’s __call__ method.
      • cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)

Method 4: Use a Base Class


class Singleton: _instance = None def __new__(class_, *args, **kwargs): if not isinstance(class_._instance, class_): class_._instance = object.__new__(class_, *args, **kwargs) return class_._instance class MyClass(Singleton): pass
x = MyClass()
y = MyClass()
x.val=4
x is y, y.val

The output is as follows:

(True, 4)

Pros

  • Code can be reused to create more singletons
  • Uses familiar tools. (Compared to decorators, metaclasses and the __new__ method)

In all four methods, an instance is created the first time it is asked for one. All calls after the first return the first instance.

Singletons in a Threaded Environment


If your Singleton needs to operate in a multi-threaded environment, then your Singleton method needs to be made thread-safe. None of the methods above is thread-safe. The vulnerable code is found between the check of an existing Singleton and the creation of the first instance:

if cls._instance is None: cls._instance = super(Singleton, cls).__new__(cls)

Each implementation has a similar piece of code. To make it thread-safe, this code needs to be synchronized.

with threading.Lock(): if cls._instance is None: cls._instance = super(Singleton, cls).__new__(cls)


This works fine and with the lock in place, the Singleton creation becomes thread-safe. Now, every time a thread runs the code, the threading.Lock() is called before it checks for an existing instance.

If performance is not an issue, that’s great, but we can do better. The locking mechanism is expensive and it only needs to run the first time. The instance creation only happens once so the lock should happen at most one time. The solution is to place the lock after the check statement. Then add another check after the lock.

import threading
... if cls._instance is None: with threading.Lock(): if cls._instance is None: cls._instance = super(Singleton, cls).__new__(cls)

And that is how to use “Double-checked locking“.

Thread-Safe Version of Method 1


Consider the following modification of method 1:

import threading
class Singleton: _instance = None def __new__(cls): if cls._instance is None: with threading.Lock(): if cls._instance is None: cls._instance = super(Singleton, cls).__new__(cls) # Initialize here. No need to use __init__().. cls.val = 0 return cls._instance def business_method(self, val): self.val = val x = Singleton()
y = Singleton()
x.val = 42
x is y, y.val

The output is:

(True, 42)

To make it thread-safe, we added two lines of code. Each method could be made thread-safe in a similar way

Alternatives to using a Singleton


Use a Module as a Singleton (The Global Object Pattern)


In Python, modules are single, unique, and globally available. The Global Object Pattern is recommended by the Python docs. It simply means to create a separate module and instantiate your object in the module’s global space. Subsequent references just need to import it.

Use Dependency Injection


Generally, this means using composition to provide objects to dependent objects. It can be implemented in countless ways but generally, put dependencies in constructors and avoid creating new instances of objects in business methods.

The Problems With Singletons


Of all 23 patterns in the seminal 1994 book Design Patterns, Singleton is the most used, the most discussed, and the most panned. It’s a bit of a rabbit hole to sift through the thousands of blogs and Stack Overflow posts that talk about it. But after all the Singleton hating, the pattern remains common. Why is that? It’s because conditions that suggest its use are very common: One database, one config file, one thread pool …

The arguments against its use are best stated in some elegant (and old) blog posts that I cannot match. But I will give a summary and links for further reading.

Concise Summary


Paraphrased from Brian Button in Why Singletons are Evil:

  1. They are generally used as a global instance, why is that so bad? Because you hide the dependencies of your application in your code, instead of exposing them through the interfaces. Making something global to avoid passing it around is a code smell. (That is some effective name-calling. Whatever code smell is, it makes me cringe just a bit and wrinkle my nose as I imagine it).
  2. They violate the single responsibility principle: by virtue of the fact that they control their own creation and lifecycle.
  3. They inherently cause code to be tightly coupled. This makes faking them out under test rather difficult in many cases.
  4. They carry state around for the lifetime of the application. Another hit to testing since you can end up with a situation where tests need to be ordered which is a big no no for unit tests. Why? Because each unit test should be independent from the other.

Should You Use Singletons in Your Code?


If you are asking yourself that based on the other peoples’ blogs, you are already in the rabbit hole. The word ‘should’ is not welcome in code design. Use singletons or not and be aware of possible problems. Refactor when there are problems.

Possible Problems to Consider


Tools are for people who know how to use them. In spite of all the bad stuff written about Singletons, people still use them because:

  1. They fill a need better than the alternatives.

and / or

  1. They don’t know any better and they are creating problems in their code by using them.

Avoid problems. Don’t be in group 2.

Problems with Singletons are caused because they break the single responsibility rule. They do three things:

  1. Guarantee only a single instance exists
  2. Provide global access to that instance
  3. Provide their own business logic.
  • Because they break the single responsibility rule, Singletons may be hard to test
    • Inversion of control IoC and dependency injection are patterns meant to overcome this problem in an object-oriented manner that helps to make testable code.
  • Singletons may cause tightly coupled code. A global instance that has an inconstant state may require an object to depend on the state of the global object.
  • It is an OO principal to Separate Creational Logic from Business Logic. Adhering to this principle “Singletons should never be used”. Again with the word should. Instead, Be Yoda: “Do or do not!“. Base the decision on your own code.
  • Memory allocated to a Singleton can’t be freed. This is only a problem it the memory needs to be freed.
    • In a garbage collected environment singletons may become a memory management issue.

Further Study


Meta notes — Miško Hevery.


Hevery worked at Google when he wrote these blogs. His blogs were readable, entertaining, informative, provocative, and generally overstated to make a point. If you read his blogs, be sure to read the comments. Singletons are Pathological Liars has a unit testing example that illustrates how singletons can make it difficult to figure out dependency chains and start or test an application. It is a fairly extreme example of abuse, but he makes a valid point:

Singletons are nothing more than global state. Global state makes it so your objects can secretly get hold of things which are not declared in their APIs, and, as a result, Singletons make your APIs into pathological liars.

Of course, he is overstating a bit. Singletons wrap global state in a class and are used for things that are ‘naturally’ global by nature. Generally, Hevery recommends dependency injection to replace Singletons. That simply means objects are handed their dependencies in their constructor.

Where have all the singletons gone makes the point that dependency injection has made it easy to get instances to constructors that require them, which alleviates the underlying need behind the bad, global Singletons decried in the Pathological Liars.

Meta notes — Brandon Rhodes The Singleton Pattern


Python programmers almost never implement the Singleton Pattern as described in the Gang of Four book, whose Singleton class forbids normal instantiation and instead offers a class method that returns the singleton instance. Python is more elegant, and lets a class continue to support the normal syntax for instantiation while defining a custom __new__() method that returns the singleton instance. But an even more Pythonic approach, if your design forces you to offer global access to a singleton object, is to use The Global Object Pattern instead.

Meta notes — J.B. Rainsberger Use your singletons wisely


Know when to use singletons, and when to leave them behind

J.B. Rainsberger

Published on July 01, 2001 Automated unit testing is most effective when:

  • Coupling between classes is only as strong as it needs to be
  • It is simple to use mock implementations of collaborating classes in place of production implementations
Singletons know too much

There is one implementation anti-pattern that flourishes in an application with too many singletons: the I know where you live anti-pattern. This occurs when, among collaborating classes, one class knows where to get instances of the other.

Towards acceptible singletons

Singleton abuse can be avoided by looking at the problem from a different angle. Suppose an application needs only one instance of a class and the application configures that class at startup: Why should the class itself be responsible for being a singleton? It seems quite logical for the application to take on this responsibility, since the application requires this kind of behavior. The application, not the component, should be the singleton. The application then makes an instance of the component available for any application-specific code to use. When an application uses several such components, it can aggregate them into what we have called a toolbox.

Meta notes — Mark Safayan Singleton anti pattern


Instead of using this pattern, simply instantiate a single instance and propagate it to places that use the object as a parameter to make the dependency explicit.



https://www.sickgaming.net/blog/2020/09/...in-python/
Reply



Possibly Related Threads…
Thread Author Replies Views Last Post
  [Tut] Python’s NameError: name ‘xxx’ is not defined — How to Fix This Stupid Bug? xSicKxBot 0 8 10-16-2020, 10:30 PM
Last Post: xSicKxBot
  [Tut] Python IndentationError: unexpected indent (How to Fix This Stupid Bug) xSicKxBot 0 17 10-10-2020, 08:24 PM
Last Post: xSicKxBot
  [Tut] Yield Keyword in Python – A Simple Illustrated Guide xSicKxBot 0 18 10-09-2020, 06:13 PM
Last Post: xSicKxBot
  [Tut] Python Reverse List with Slicing — An Illustrated Guide xSicKxBot 0 29 10-02-2020, 04:24 AM
Last Post: xSicKxBot
  [Tut] How to Remove Duplicates From a Python List While Preserving Order? xSicKxBot 0 31 10-01-2020, 02:21 AM
Last Post: xSicKxBot
  [Tut] How To Update A Key In A Dictionary In Python If The Key Doesn’t Exist? xSicKxBot 0 32 09-29-2020, 09:02 PM
Last Post: xSicKxBot
  [Tut] How to Get the Last Element of a Python List? xSicKxBot 0 34 09-28-2020, 02:36 AM
Last Post: xSicKxBot
  [Tut] How To Format A String That Contains Curly Braces In Python? xSicKxBot 0 31 09-25-2020, 07:51 PM
Last Post: xSicKxBot
  [Tut] Python One Line Dictionary xSicKxBot 0 38 09-21-2020, 05:58 PM
Last Post: xSicKxBot
  [Tut] Python Import Error (ModuleNotFoundError) xSicKxBot 0 33 09-20-2020, 04:15 PM
Last Post: xSicKxBot

Forum Jump:

Become a Patron!
[-]
Upcoming Events

[-]
Latest Threads
Mobile - Win yourself a free copy of sha...
Last Post: xSicKxBot
Today 09:07 AM
» Replies: 0
» Views: 0
[Tut] Top 3 Freelance Developer Contract...
Last Post: xSicKxBot
Today 04:49 AM
» Replies: 0
» Views: 0
(Indie Deal) Alien Cat Bundle, RIDE 4 re...
Last Post: xSicKxBot
Today 04:48 AM
» Replies: 0
» Views: 1
News - Super Smash Bros. Ultimate 9.0.1...
Last Post: xSicKxBot
Today 04:48 AM
» Replies: 0
» Views: 1
Unity Mega Bundle X 10th Anniversary Sal...
Last Post: xSicKxBot
Today 01:02 AM
» Replies: 0
» Views: 3
Microsoft - Fundraising and Engagement f...
Last Post: xSicKxBot
Today 01:02 AM
» Replies: 0
» Views: 2
Fedora - Incremental backup with Butterf...
Last Post: xSicKxBot
Today 01:01 AM
» Replies: 0
» Views: 2
News - Review: Horace – A Heart-Warming ...
Last Post: xSicKxBot
Yesterday 11:38 PM
» Replies: 0
» Views: 2
News - Matthew McConaughey Explains The ...
Last Post: xSicKxBot
Yesterday 10:20 PM
» Replies: 0
» Views: 3
PlanetSide 2 External Hack / Mod
Last Post: FarCry10
Yesterday 05:27 PM
» Replies: 6
» Views: 6812

[-]
Twitter

[-]
Sponsored
Get the Deal of the Week at RefurBees.com

Copyright © SickGaming.net 2012-2020