Saturday, November 16, 2024
Google search engine
HomeLanguagesClass Factories: A powerful pattern in Python

Class Factories: A powerful pattern in Python

A Class Factory is a function that creates and returns a class. It is one of the powerful patterns in Python. In this section, we will cover how to design class factories and the use cases of it.

Designing a Class Factory 

As mentioned, class factories are functions that create and return a class. It can create a class at the coding time (using class keyword) and as well as during run time (using the type). Let’s start with how to design a class factory and create a class at the coding time, then we look into the scenario of creating a class during run time.

Class Factory and class keyword

Designing a class factory using the class keyword is nothing but creating a function that holds a class. Let’s see the below code:

Python3




def apple_function():
    """Return an Apple class, built using the 
    class keyword"""
    class Apple(object):
        def __init__(self, color):
            self.color = color
  
        def getColor(self):
            return self.color
    return Apple
  
  
# invoking class factory function
Apple = apple_function()
appleObj = Apple('red')
print(appleObj.getColor())


Output

red

Class Factory and type

Using type we can create classes dynamically. But doing so will leave the functions in the namespace along with the class. Let’s look into the code to understand it better.

Python3




def init(self, color):
    self.color = color
  
  
def getColor(self):
    return self.color
  
  
Apple = type('Apple', (object,), {
    '__init__': init,
    'getColor': getColor,
})
  
appleRed = Apple(color='red')
print(appleRed.getColor())


Output

red

The above code shows how to create class dynamically. But the problem is that the functions such as init and getColor are cluttering the namespace and also we won’t be able to reuse the functionality. Whereas, by using a class factory, you can minimize the clutter and can reuse the function when in need. Let’s look at the below code.

Python3




def create_apple_class():
    def init(self, color):
        self.color = color
  
    def getColor(self):
        return self.color
  
    return type('Apple', (object,), {
        '__init__': init,
        'getColor': getColor,
    })
  
  
Apple = create_apple_class()
appleObj = Apple('red')
print(appleObj.getColor())


Output

red

It is important to note that multiple calls to create_apple_class will return distinct classes.

When you should write Class Factories

Let’s have a look at some of the use cases of class factories. Class Factories are useful when you do not know what attributes to be assigned at the time of coding 

Runtime Attributes

Class Factories are necessary when attributes of the class differ based on the requirement.  Let’s consider the case of a login process. Here, we will consider two scenarios, either traditional login or using an OpenId service. If we look into traditional login, the parameters are username and password, and additionally, it may have two-factor authentication. And, for OpenId service, the parameters are service name and email address. This two login scenario points to the fact that attributes of a class differ based on the login service. Let’s look in the below sample code:  

Python3




def credentials_cls(need_proxy=False, tfa=False):
    # need proxy for openId services
    if need_proxy:
        print("Open Id Service")
        keys = ['service_name', 'email_address']
    else:
        print("Traditional Login")
        keys = ['username', 'password']
  
        # two factor authentication for traditional login
        if tfa:
            keys.append('auth_token')
  
    class CredentialCheck(object):
        required_keys = set(keys)
  
        def __init__(self, **kwargs):
            # checking whether key matches based on login service
            if self.required_keys != set(kwargs.keys()):
                raise ValueError('Mismatch')
  
            # storing the keys and values to the credential object
            for k, v in kwargs.items():
                setattr(self, k, v)
  
    return CredentialCheck
  
  
CredCheck = credentials_cls(False, False)
crdTraditional = CredCheck(username='uname', password='******')
  
OpenIDCheck = credentials_cls(True, False)
crdOpenID = OpenIDCheck(service_name='sname', email_address='email@gmail.com')


Output

Traditional Login
Open Id Service

Modify Class Attributes

Another advantage of using class attributes is that it can deal with class attributes and can distinguish them from class instances. Let’s consider the scenario where a class defines a class method. Class methods are methods that require the class itself for execution rather than the instance of a class. You can design a class method by decorating a method using @classmethod decorator. Let’s look at the below code.

Python3




class Apple(object):
    color = 'red'
  
    @classmethod
    def classapple(cls):
        return cls.color
  
  
appleRed = Apple()
appleYellow = Apple()
appleGreen = Apple()
  
print("Apple Red: ", appleRed.classapple())
  
appleYellow.color = 'Yellow'
print("Apple Yellow: ", appleYellow.classapple())
  
appleGreen.color = 'Green'
print("Apple Green: ", appleGreen.classapple())


Output

Apple Red:  red
Apple Yellow:  red
Apple Green:  red

In the above code, we have designed a class called Apple that has color as an attribute. In addition to this, we have declared a class method called classapple using the decorator @classmethod. The functionality of classapple method is to return the color of the apple. But, you can note that even after setting the color of apple to Yellow and Green, the object returns the default color red. This limitation can be overcome using a class factory. 

Let’s see the below code that defines a class factory called create_Apple_subclass. Here we will create a subclass of Apple, subApple, to set the color. Finally, the class factory returns the subclass. 

Python3




class Apple(object):
    color = 'red'
  
    @classmethod
    def classapple(cls):
        return cls.color
  
  
def create_Apple_subclass(new_color):
    class SubApple(Apple):
        color = new_color
    return SubApple
  
  
sappleYellow = create_Apple_subclass('Yellow')
print("Apple Color: ", sappleYellow.classapple())
  
sappleGreen = create_Apple_subclass('Green')
print("Apple Color: ", sappleGreen.classapple())


Output

Apple Color:  Yellow
Apple Color:  Green

Summary

Class factories are powerful design patterns that ensure a dynamic class creation process is readable, organized, and reusable. And, also class factories allow attribute switching based on the parameter sent to the function.

RELATED ARTICLES

Most Popular

Recent Comments