Singleton in python examples

Making a singleton in Python

Sign in to your Python Morsels account to save your screencast settings.

How can you make a singleton in Python?

What is a singleton?

A singleton class is a class that only allows creating one instance of itself.

None is an example of a singleton object in Python. The class of None is NoneType :

If we try to call the NoneType class, we’ll get back an instance of that class.

But every instance of the NoneType class is identical to every other instance of the NoneType class:

So there’s only one instance of NoneType in Python, and it’s None .

Making a singletons in Python with a custom constructor

Here we have a class called EventTracker that helps us keep track of events in our application:

class EventTracker: def __init__(self): self.api_url = "http://example.com" def track(self): print(f"TODO track event at self.api_url>") 

We’d like to share just one instance of this class for our whole Python process. To do that, we could make a singleton class which only allows one instance of itself to be created.

We can make a singleton class by customizing our class to have a custom constructor method:

class EventTracker: _self = None def __new__(cls): if cls._self is None: cls._self = super().__new__(cls) return cls._self def __init__(self): self.api_url = "http://example.com" def track(self): print(f"TODO track event at self.api_url>") 

Python’s __init__ method is called the initializer method.

By the time the __init__ method gets called, our class instance has already been constructed. That’s what the self argument in a method is:

The __new__ method is the constructor method. Its job is to do the actual work of constructing and then returning a new instance of our class:

class EventTracker: _self = None def __new__(cls): if cls._self is None: cls._self = super().__new__(cls) return cls._self . 

In this EventTracker class, our constructor method case always returns the same instance of our class.

If it doesn’t have a class instance yet, it calls its parent class’s constructor (that’s object.__new__ since object is the parent class of all Python classes by default):

 if cls._self is None: cls._self = super().__new__(cls) 

If we do already have a class instance, we just return it:

So every «instance» of our class is actually the same instance.

Meaning when we first call our class, we’ll get back a new instance:

>>> tracker = EventTracker() >>> tracker 

But if we call our class a second time, we’ll get back the same exact instance:

>>> tracker2 = EventTracker() >>> tracker2 >>> tracker2 is tracker True 

Every instance of our class is the same, which means we’ve made a singleton class.

We could use a global object instead

Creating a singleton class by making a custom constructor does work, but it might seem a little bit misleading to someone using this class. It’s counter-intuitive that every time we call our class we’ll always get back the same class instance.

The singleton pattern usually doesn’t make sense in Python in its purest form. Instead, it usually makes more sense to make a single instance of a class, and then assign that instance to a global variable in our module.

Here we’ve renamed our class to _EventTracker (putting an _ prefix just before it to denote «private by convention»):

class _EventTracker: def __init__(self): self.api_url = "http://example.com" def track(self): print(f"TODO track event at self.api_url>") tracker = _EventTracker() 

It isn’t strictly necessary to rename your class, but it does let people know that you’re not actually meant to use the class directly. You’re only ever meant to interact with this one instance.

When using our class, we won’t actually interact with the class directly. Instead we would import and use just the single class instance we’ve made:

>>> from events import tracker >>> tracker.track() TODO track event at http://example.com 

Do we even need a singleton class?

If there’s never any reason to have two instances of your class, you might consider not making a class at all and instead just use the global state within your module.

Here we’ve made an events module that does the same thing as our events module before:

api_url = "http://example.com" def track(): print(f"TODO track event at api_url>") 

But we don’t have a class. Instead, we’ve taken the state and the functionality that was within that class, and we’ve put it at the module level.

To use this module, instead of saying events.tracker.track() like we would’ve done before, we can just use events.track() :

>>> import events >>> events.track() TODO track event at http://example.com 

We’re now calling our track function at the module level.

Now, this works for the same reason that making global object works: modules in Python act like singletons!

Python’s modules act like singletons

Classes are handy, but you don’t always need a class in Python.

When you import a module, Python will run the code within that module and create a new module object:

But if we import the same module again, Python will give us back the exact same module object:

>>> import events as again >>> again  >>> again is events True 

So if we change some of the global state within one of these module objects:

>>> again.api_url 'http://example.com' >>> again.api_url = "NEW URL" 

That change would be reflected in the other object as well (because those two variables point to the same object):

For each Python module, there is only ever one module object.

So if you need to share global state in Python, it’s often simplest to just use the global variables within a module.

Modules are the most typical Python singleton

The classic singleton design pattern doesn’t always make a lot of sense in Python.

Singletons are most often used for sharing global state. In Python, if you need to share some global state, you can often just use a module object because in Python modules are singletons.

A Python tip every week

Need to fill-in gaps in your Python skills?

Sign up for my Python newsletter where I share one of my favorite Python tips every week.

Series: Classes

Classes are a way to bundle functionality and state together. The terms «type» and «class» are interchangeable: list , dict , tuple , int , str , set , and bool are all classes.

You’ll certainly use quite a few classes in Python (remember types are classes) but you may not need to create your own often.

To track your progress on this Python Morsels topic trail, sign in or sign up.

Источник

Python and the Magic Singleton

Asaf Gur

Python and the Magic Singleton

If you have been writing code for a while now, you must have encountered design patterns. The most simple of them is the singleton.
From Wikipedia:

The singleton pattern is a software design pattern that restricts the instantiation of a class to one object.

You should use the singleton pattern when your app needs a globally accessible, lazy loaded object that has only one instance.

Some people might tell you that using a singleton in python is strictly unnecessary. Well, that’s just wrong. The necessity of the solution always depends on the problem.
If you only need global accessible object, you can use globals. If you don’t care about lazy loading, you can use a module or a “static” class. There’s lots of possibilites.
In my opinion — if it fits, and it makes your code nicer, go for it.
From the Zen of Python:

“If the implementation is easy to explain, it may be a good idea.”

Implementation

If you google “python singleton”, you will find a lot of different implementations for the singleton pattern. This one is my favorite:

 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] 

A Metaclass can customize another class’s creation process. It can be a bit confusing, as it is one of the magic features that python has and most programming languages doesn’t have. Basically, it’s the class of the class. Confused? Let’s perform a little experiment and try to understand what’s going on.

It’s Magic!

Let’s try the following code:

 class MyMeta(type):   def __call__(cls, *args, **kwargs):  print('meta!')  class MyClass(metaclass=MyMeta):   def __init__(self):  print('class')  if __name__ == '__main__':  c = MyClass()  print(c) 

Here, we defined a metaclass that prints out ‘metaclass’ and a class that prints class. Note that we are overriding the magic function __call__. The __call__ function executes whenever you call on object. In aspect of classes this means that MyClass() is equivalent to MyClass.call().

The code above outputs the following:

So.. Why is the variable c actually None… ?
This happens because our __call__ function doesn’t return anything. Pretty cool right? You can prank your friends and make their code not work until they find the metaclass definition ( please don’t! 🙂 )

Let’s go ahead and fix that __call__ function:

 class MyMeta(type):   def __call__(cls, *args, **kwargs):  print('meta!')  return super(MyMeta, cls).__call__(*args, **kwargs) # call the class's __call__ manually  class MyClass(metaclass=MyMeta):   def __init__(self):  print('class')  if __name__ == '__main__':  c = MyClass()  print(c) 

Success! we customized the class instantiation process. Now, we can understand our Singleton metaclass much better. The metaclass makes a single instance and returns that whenever you call the class.
You can do whatever comes to mind with __call__ functions, Python is not very restrictive. However, you should be very careful. As we know, code is more read than written and intuitivity is important.

When Magic Becomes Voodoo

There’s a downside to the metaclass singleton implementation, it’s implicit. Consider the following example (MyClass is our singleton from before):

 # lots of code here  c = MyClass()  def some_function():  # some code  a = MyClass()  # some more code  # lots of code  class AnotherClass(object):   def __init__(self, *args):  self._d = MyClass()  # more code  # you got it.. more code 

We are using our new singleton implementation in a large project, maybe even tens of thousands of lines of code. Now, a new coder joins the team and reads the code. Do you think he/she will be able to easily tell that MyClass is a singleton?
The answer to that is no in 99% of the cases.
So, what can we do to make our singleton more explicit?
Here is one solution:

 class MyClass(metaclass=MyMeta):   def __init__(self):  print('class')   @classmethod  def get_instance(cls):  return MyClass()  # instead of calling MyClass() we'll call MyClass.get_instance() 

The get_instance class method makes it very clear that this is in fact a singleton. Sure, you could call MyClass() and it would give you the same result. However, making your code more explicit usually makes it more easy to understand.

Summary

I hope you share my opinions about singletons, magic and voodoo. Of course if you don’t I will be very happy to hear about it.

I hope you enjoyed, and as always, feel free to comment or share.
Thank you for reading.

Источник

Читайте также:  Html script async src
Оцените статью