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?

<div><p>Master coders behave like architects that connect and build upon various <strong><em>design patterns</em></strong> to create a functional whole. One of the most important design patterns is a <strong><em>singleton</em></strong>—a class that has only one instance. You may ask: <em><strong>How does that look like?</strong></em> Let’s have a look at the code implementing a singleton in our interactive code shell:</p>
<p> <iframe height="700px" width="100%" src="https://repl.it/@finxter/singleton?lite=true" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"></iframe> </p>
<p><em><strong>Exercise</strong>: Try to create multiple instances of the singleton class. Can you do it?</em></p>
<p>Let’s dive into a deeper understanding of the singleton. We’ll discuss this code in our first method, so keep reading!</p>
<h2>What’s a Singleton? </h2>
<p>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 <a href="https://en.wikipedia.org/wiki/Design_Patterns">Gang of Four</a>. 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 <a href="https://www.goodreads.com/book/show/58128.Head_First_Design_Patterns">Head First Design Patterns</a>:</p>
<blockquote class="wp-block-quote">
<p>The Singleton Pattern ensures a class has only one instance, and provides a global point of access to it.</p>
</blockquote>
<h2 id="Why-would-you-need-a-singleton?">Why Would You Need a Singleton?</h2>
<p>If you are reading this, you likely already have a possible use. Singleton is one of the Gang of Four’s <em>Creational</em> patterns. Read on to determine if its a good candidate for the problem you need to solve.</p>
<p>A singleton can be used to access a common resource like a database or a <a href="https://blog.finxter.com/python-one-liner-write-string-to-file/" title="Python One-Liner: Write String to File" target="_blank" rel="noreferrer noopener">file</a>. 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 <strong><em>The Zen of Python</em></strong> (Pythonistas say Ohm):</p>
<ul>
<li>Simple is better than complex</li>
<li>Practicality beats purity</li>
</ul>
<p>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 <a href="https://blog.finxter.com/object-oriented-programming-terminology-cheat-sheet/" target="_blank" rel="noreferrer noopener" title="[Python OOP Cheat Sheet] A Simple Overview of Object-Oriented Programming">Object Oriented</a> principals and unit testing.</p>
<p>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:</p>
<ul>
<li>Logger</li>
<li>Thread pools</li>
<li>caches</li>
<li>dialog boxes</li>
<li>An Http client</li>
<li>handles to preference settings</li>
<li>objects for logging</li>
<li>handles for device drivers like printers.</li>
<li>(?) Any single resource or global collection</li>
</ul>
<p>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.</p>
<p>And finally, a singleton can be a part of a larger design pattern. It may be part of any of the following patterns:</p>
<ul>
<li>abstract factory pattern</li>
<li>builder pattern</li>
<li>prototype pattern</li>
<li>facade pattern</li>
<li>state objects pattern If you have not heard of these, no worries. It won’t affect your understanding of the singleton pattern.</li>
</ul>
<h2 id="Implementation">Implementation</h2>
<p>The standard C# and Java implementations rely on creating a class with a private constructor. Access to the object is given through a method: <code>getInstance()</code></p>
<h5 id="Here-is-a-typical-lazy-singleton-implementation-in-Java">Here is a typical lazy singleton implementation in Java:</h5>
<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public Singleton { private static Singleton theOnlyInstance; private Singleton() {} public static Singleton getInstance() { if (theOnlyInstance) == null){ theOnlyInstance = new Singleton() } return new Singleton(); }
}</pre>
<p>There are many ways to implement <strong><em>Singleton in Python</em></strong>. I will show all four first and discuss them below.</p>
<h2 id="Method-1,-use-__new__:">Method 1: Use __new__</h2>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">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</pre>
<p>It uses the Python <a href="https://blog.finxter.com/underscore-in-python/" title="The Single and Double Underscore in Python [“_” vs “__”]" target="_blank" rel="noreferrer noopener">dunder </a><code>__new__</code> that was added to Python to provide an alternative object creation method. This is the kind of use case <code>__new__</code> was designed for</p>
<p><strong>Pros</strong>:</p>
<ul>
<li>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.
<ul>
<li>Easy to understand code meaning is important for teams and maintenance.</li>
</ul>
</li>
<li>Uses one class to create and implement the Singleton.</li>
</ul>
<p><strong>Cons</strong>:</p>
<ul>
<li>In spite of its ‘correctness’ many python coders will have to look up <code>__new__</code> to understand the object creation specifics. Its enough to know that
<ol>
<li><code>__new__</code> instantiates the object.</li>
<li>Code that normally goes in <code>__init__</code> can be placed in <code>__new__</code>.</li>
<li>In order to work correctly the overridden <code>__new__</code> must call its parent’s <code>__new__</code> method. In this case, object is the parent. Instantiaion happens here with this line:
<ul>
<li><code>object.__new__(class_, *args, **kwargs)</code></li>
</ul>
</li>
</ol>
</li>
</ul>
<h2 id="Method-2,-a-decorator">Method 2: A Decorator</h2>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">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)</pre>
<p><strong>Pros</strong></p>
<ul>
<li>The code to write the decorator is separate from the class creation.</li>
<li>It can be reused to make as many singletons as you need.</li>
<li>The singleton decorator marks an intention that is clear and understandable</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li>The call <code>type(MyClass)</code> will resolve as <em>function</em>.
<ul>
<li>Creating a class method in <code>MyClass</code> will result in a syntax error.</li>
</ul>
</li>
</ul>
<p>If you really want to use a decorator and must retain class definition, there is a way. You could use this library:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">pip install singleton_decorator</pre>
<p>The library <code>singleton_decorator</code> <a href="https://github.com/Kemaweyan/singleton_decorator/blob/master/singleton_decorator/decorator.py">wraps and renames</a> the singleton class. Alternately you can write your own. Here is an implementation:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">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</pre>
<p>The output is:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">(True, 42)</pre>
<p><em><strong>Interactive Exercise</strong>: Run the following interactive memory visualization. How many singleton instances do you find?</em></p>
<p> <iframe width="800" height="900" frameborder="0" src="https://pythontutor.com/iframe-embed.html#code=def%20singleton%28Cls%29%3A%0A%20%20%20%20singletons%20%3D%20%7B%7D%0A%20%20%20%20def%20getinstance%28*args,%20**kwargs%29%3A%0A%20%20%20%20%20%20%20%20if%20Cls%20not%20in%20singletons%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20singletons%5BCls%5D%20%3D%20Cls%28*args,%20**kwargs%29%0A%20%20%20%20%20%20%20%20return%20singletons%5BCls%5D%0A%20%20%20%20%0A%20%20%20%20return%20getinstance%0A%0A%40singleton%0Aclass%20MyClass%3A%0A%20%20%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%20%20%20%20self.val%20%3D%203%0A%0Ax%20%3D%20MyClass%28%29%0Ay%20%3D%20MyClass%28%29%0Ax.val%20%3D%2042%0Ax%20is%20y,%20y.val,%20type%28MyClass%29&codeDivHeight=400&codeDivWidth=350&cumulative=false&curInstr=0&heapPrimitives=nevernest&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe> </p>
<h2 id="Method-3,-use-metaclass,-inherit-from-type-and-override-__call__-to-trigger-or-filter-instance-creation.">Method 3: Use Metaclass and Inherit From Type and Override __call__ to Trigger or Filter Instance Creation</h2>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">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</pre>
<p>The output is as follows:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">(True, 4)</pre>
<p>Method 3 creates a new <a href="https://realpython.com/python-metaclasses/#custom-metaclasses">custom metaclass</a> by inheriting from type. MyClass then assigns Singleton as its metadata:</p>
<p><code>class MyClass(metadata = Singleton):</code></p>
<p>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 <code>__call__</code> method, <code>super.__call__</code> is called to create the class instance. See <a href="https://realpython.com/python-metaclasses/#custom-metaclasses">custom metaclass</a> to better understand the <code>__call__</code> method.</p>
<p><strong>Pros</strong></p>
<ul>
<li>Singleton code is separate. Multiple singletons can be created using the same</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li>Metaclasses remain mysterious for many python coders. Here is what you need to know:
<ul>
<li>In this implementation, type is inherited:
<ul>
<li><code>class Singleton(type)</code></li>
</ul>
</li>
<li>In order to work correctly the overridden <code>__call__</code> must call its parent’s <code>__call__</code> method.
<ul>
<li><code>cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)</code></li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="Method-4-uses-a-Base-class">Method 4: Use a Base Class</h2>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">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</pre>
<p>The output is as follows:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">(True, 4)</pre>
<p><strong>Pros</strong></p>
<ul>
<li>Code can be reused to create more singletons</li>
<li>Uses familiar tools. (Compared to decorators, metaclasses and the <code>__new__</code> method)</li>
</ul>
<p>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.</p>
<h2 id="Singletons-in-a-threaded-environment">Singletons in a Threaded Environment</h2>
<p>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:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">if cls._instance is None: cls._instance = super(Singleton, cls).__new__(cls)</pre>
<p>Each implementation has a similar piece of code. To make it thread-safe, this code needs to be synchronized.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">with threading.Lock(): if cls._instance is None: cls._instance = super(Singleton, cls).__new__(cls)
</pre>
<p>This works fine and with the lock in place, the Singleton creation becomes thread-safe. Now, every time a thread runs the code, the <code>threading.Lock()</code> is called before it checks for an existing instance.</p>
<p>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.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import threading
... if cls._instance is None: with threading.Lock(): if cls._instance is None: cls._instance = super(Singleton, cls).__new__(cls)</pre>
<p>And that is how to use “<a href="https://en.wikipedia.org/wiki/Double-checked_locking">Double-checked locking</a>“.</p>
<h3 id="Thread-safe-version-of-method-1">Thread-Safe Version of Method 1</h3>
<p>Consider the following modification of method 1:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">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</pre>
<p>The output is:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">(True, 42)</pre>
<p>To make it thread-safe, we added two lines of code. Each method could be made thread-safe in a similar way</p>
<h2 id="Alternatives-to-using-a-Singleton">Alternatives to using a Singleton</h2>
<h3 id="Use-a-module-as-a-Singleton-(The-Global-Object-Pattern)">Use a Module as a Singleton (The Global Object Pattern)</h3>
<p>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.</p>
<h3 id="Use-dependency-injection.">Use Dependency Injection</h3>
<p>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.</p>
<h2 id="The-problems-with-singletons">The Problems With Singletons</h2>
<p>Of all 23 patterns in the seminal 1994 book <a href="https://en.wikipedia.org/wiki/Design_Patterns">Design Patterns</a>, 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 …</p>
<p>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.</p>
<h2 id="Concise-summary">Concise Summary</h2>
<p>Paraphrased from Brian Button in <a href="https://docs.microsoft.com/en-us/archive/blogs/scottdensmore/why-singletons-are-evil">Why Singletons are Evil</a>:</p>
<ol>
<li>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).</li>
<li>They violate the single responsibility principle: by virtue of the fact that they control their own creation and lifecycle.</li>
<li>They inherently cause code to be tightly coupled. This makes faking them out under test rather difficult in many cases.</li>
<li>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.</li>
</ol>
<h2 id="Should-you-use-Singletons-in-your-code?">Should You Use Singletons in Your Code?</h2>
<p>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.</p>
<h2 id="Possible-problems-to-consider:">Possible Problems to Consider</h2>
<p>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:</p>
<ol>
<li>They fill a need better than the alternatives.</li>
</ol>
<p>and / or</p>
<ol>
<li>They don’t know any better and they are creating problems in their code by using them.</li>
</ol>
<p>Avoid problems. Don’t be in group 2.</p>
<p>Problems with Singletons are caused because they break the single responsibility rule. They do three things:</p>
<ol>
<li>Guarantee only a single instance exists</li>
<li>Provide global access to that instance</li>
<li>Provide their own business logic.</li>
</ol>
<ul>
<li>Because they break the single responsibility rule, Singletons may be hard to test
<ul>
<li>Inversion of control <a href="http://en.wikipedia.org/wiki/Inversion_of_control">IoC</a> and <a href="http://en.wikipedia.org/wiki/Dependency_injection">dependency injection</a> are patterns meant to overcome this problem in an object-oriented manner that helps to make testable code.</li>
</ul>
</li>
<li>Singletons may cause tightly <a href="https://en.wikipedia.org/wiki/Coupling_%28computer_programming%29">coupled code</a>. A global instance that has an inconstant state may require an object to depend on the state of the global object.</li>
<li>It is an OO principal to <a href="https://www.codeproject.com/Articles/768052/Golden-Rules-Of-Good-OOP">Separate Creational Logic from Business Logic</a>. Adhering to this principle “Singletons <strong><em>should</em></strong> never be used”. Again with the word should. Instead, Be Yoda: “<em>Do or do not!</em>“. Base the decision on your own code.</li>
<li>Memory allocated to a Singleton can’t be freed. This is only a problem it the memory needs to be freed.
<ul>
<li>In a <a href="https://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29">garbage collected</a> environment singletons may become a memory management issue.</li>
</ul>
</li>
</ul>
<h2 id="Further-study">Further Study</h2>
<ul>
<li>Brandon Rhodes, <a href="https://python-patterns.guide/gang-of-four/singleton/">The Singleton Pattern</a></li>
<li>Miško Hevery, <a href="http://geekswithblogs.net/AngelEyes/archive/2013/09/08/singleton-i-love-you-but-youre-bringing-me-down-re-uploaded.aspx">singleton I Love You-But You’re Bringing Me Down</a>. Reposted with comments</li>
<li>Miško Hevery, <a href="http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/">Singletons are Pathological Liars</a></li>
<li>Miško Hevery, <a href="http://misko.hevery.com/2008/08/21/where-have-all-the-singletons-gone/">Where have all the singletons gone</a></li>
<li>Wikipedia <a href="https://en.wikipedia.org/wiki/Singleton_pattern">Singleton_pattern</a></li>
<li>Michael Safayan, <a href="https://www.michaelsafyan.com/tech/design/patterns/singleton">Singleton Anti-Pattern</a></li>
<li>Mark Radford <a href="https://accu.org/index.php/journals/337">Singleton, the anti-pattern</a></li>
<li>Alex Miller, <a href="http://tech.puredanger.com/2007/07/03/pattern-hate-singleton/">Patterns I Hate #1: Singleton</a></li>
<li>Scott Densmore/Brian Button, <a href="http://blogs.msdn.com/b/scottdensmore/archive/2004/05/25/140827.aspx">Why Singletons are Evil</a>
<ul>
<li>Martin Brampton, <a href="https://php-ace.com/blog/2009/09/128005/">Well used singletons are GOOD!</a></li>
</ul>
</li>
<li>A discussion edited by Cunningham &amp; Cunningham, <a href="http://c2.com/cgi/wiki?SingletonGlobalProblems">Singleton Global Problems</a></li>
<li>Robert Nystrom, <a href="http://gameprogrammingpatterns.com/singleton.html">Design Patterns Revisited: Singleton</a></li>
<li>Steve Yegge, <a href="https://sites.google.com/site/steveyegge2/singleton-considered-stupid">Singleton considered stupid</a></li>
<li>J.B. Rainsberger <a href="https://www.ibm.com/developerworks/library/co-single/">Use your singletons wisely</a></li>
</ul>
<h3 id="Meta-notes-----Miško-Hevery.">Meta notes — Miško Hevery.</h3>
<p>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. <a href="http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/">Singletons are Pathological Liars</a> 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:</p>
<blockquote class="wp-block-quote">
<p>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.</p>
</blockquote>
<p>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.</p>
<p><a href="http://misko.hevery.com/2008/08/21/where-have-all-the-singletons-gone/">Where have all the singletons gone</a> 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.</p>
<h3 id="Meta-notes----Brandon-Rhodes-The-Singleton-Pattern">Meta notes — Brandon Rhodes <a href="https://python-patterns.guide/gang-of-four/singleton/">The Singleton Pattern</a></h3>
<blockquote class="wp-block-quote">
<p>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 <code>__new__()</code> 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.</p>
</blockquote>
<h3 id="Meta-notes----J.B.-Rainsberger-Use-your-singletons-wisely">Meta notes — J.B. Rainsberger <a href="https://www.ibm.com/developerworks/library/co-single/">Use your singletons wisely</a></h3>
<p>Know when to use singletons, and when to leave them behind</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">J.B. Rainsberger
</pre>
<p>Published on July 01, 2001 Automated unit testing is most effective when:</p>
<ul>
<li>Coupling between classes is only as strong as it needs to be</li>
<li>It is simple to use mock implementations of collaborating classes in place of production implementations</li>
</ul>
<h5 id="Singletons-know-too-much">Singletons know too much</h5>
<p>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.</p>
<h5 id="Towards-acceptible-singletons">Towards acceptible singletons</h5>
<p>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.</p>
<h3 id="Meta-notes----Mark-Safayan-Singleton-anti-pattern">Meta notes — Mark Safayan <a href="https://accu.org/index.php/journals/337">Singleton anti pattern</a></h3>
<blockquote class="wp-block-quote">
<p>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.</p>
</blockquote>
</div>


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



Forum Jump:


Users browsing this thread:
3 Guest(s)

Forum software by © MyBB Theme © iAndrew 2016