Selenium and singleton in Python – part one

Going further with our series of design patterns applied in automation, in this article, we will cover one of the simplest creational patterns – Singleton.  To get a better understanding of it, we will go step by step through four ways of implementation, so we’ve split the tutorial into two parts. First, we will address the classical Singleton implementation and the lazy instantiation one and in the second part, we will use the metaclass approach and the Python decorators.

Before the actual implementation, let’s review the Singleton definition. It is aimed to deliver only one object of a given type and provides a global access point. In our ‘Selenium webdriver’ context, it allows us to control the concurrent connection with the browser driver.

As a requirement, please consider Python 3.

The classical Singleton

Implementation

Keep in mind

  • Override the __new__  dunder method to control the object creation so that we check if the object it’s already available
  • ‘hasattr’ method checks if the class already has an instance
class ClassicalSingleton(object):
     """
     Singleton class based on overriding the __new__ method
     """
     def __new__(cls):
     """
     Override __new__ method to control the obj. creation
     :return: Singleton obj.
     """
     if not hasattr(cls, 'instance'):
           cls.instance = super(ClassicalSingleton, cls).__new__(cls)

     return cls.instance

     @staticmethod
     def get_driver():
         """
         :return: Selenium driver
         """
         return webdriver.Chrome()

Usage

d1 = ClassicalSingleton()
d2 = ClassicalSingleton()
print(d1, d2) #The output will be <src.singleton.singleton_classical.ClassicalSingleton object at 0x10b969128> <src.singleton.singleton_classical.ClassicalSingleton object at 0x10b969128>

Singleton based on lazy instantiation

Implementation

To keep in mind: Lazy instantiation assures that the object is created when it’s mandatory

class LazyInstSingleton:
     __instance = None

def __init__(self):
     if LazyInstSingleton.__instance is None:
          print('__init__ method called')
     else:
          raise ValueError("An instantiation already exists!", self.get_instance())
     webdriver.Chrome()

@classmethod
def get_instance(cls):
     if cls.__instance is None:
          cls.__instance = LazyInstSingleton()
     return cls.__instance

Usage

# Below we will execute the instantiation
s = LazyInstSingleton() # class initialization
print("Obj created", LazyInstSingleton.get_instance()) # Object creation
d = LazyInstSingleton() # initialize again the class, so error will be raised
#The output will be: ValueError: ('An instantiation already exists!', <__main__.LazyInstSingleton object at 0x1108ecc50>)

In conclusion, we’ve covered two implementation methods of the singleton pattern in Python. For both of them, there is a downside, first following the classical singleton implementation, the method__new__ could be also overridden by a child class and using the lazy instantiation, it leads to an ugly code due to the necessity to call theget_instance method in order to achieve the pattern. For a better approach, I suggest following the next article, where we will cover the singleton implementation based on metaclasses and decorators.

The source code of this article could be also found here

One thought on “Selenium and singleton in Python – part one

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.