📜  类工厂: Python中强大的模式

📅  最后修改于: 2022-05-13 01:54:52.523000             🧑  作者: Mango

类工厂: Python中强大的模式

类工厂是一个创建并返回类的函数。它是Python中强大的模式之一。在本节中,我们将介绍如何设计类工厂及其用例。

设计类工厂

如前所述,类工厂是创建和返回类的函数。它可以在编码时(使用 class 关键字)和运行时(使用类型)创建一个类。先从如何在编码时设计类工厂和创建类开始,然后再看运行时创建类的场景。

类工厂和类关键字

使用 class 关键字设计类工厂只不过是创建一个包含类的函数。让我们看看下面的代码:

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())


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())


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())


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')


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())


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())


输出
red

类工厂和类型

使用类型我们可以动态创建类。但是这样做会使函数与类一起留在命名空间中。让我们查看代码以更好地理解它。

蟒蛇3

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())
输出
red

上面的代码展示了如何动态创建类。但问题是 init 和 getColor 等函数使命名空间变得混乱,而且我们将无法重用这些功能。而通过使用类工厂,您可以最大程度地减少混乱并在需要时重用该函数。让我们看看下面的代码。

蟒蛇3

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())
输出
red

需要注意的是,多次调用 create_apple_class 将返回不同的类。

什么时候应该编写类工厂

让我们来看看类工厂的一些用例。当您在编码时不知道要分配哪些属性时,类工厂很有用

运行时属性

当类的属性因需求而异时,类工厂是必要的。让我们考虑登录过程的情况。在这里,我们将考虑两种场景,传统登录或使用 OpenId 服务。如果我们看一下传统登录,参数是用户名和密码,另外,它可能有两因素身份验证。并且,对于 OpenId 服务,参数是服务名称和电子邮件地址。这两个登录场景表明一个类的属性因登录服务而异。让我们看看下面的示例代码:

蟒蛇3

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')
输出
Traditional Login
Open Id Service

修改类属性

使用类属性的另一个优点是可以处理类属性,并且可以将它们与类实例区分开来。让我们考虑一个类定义一个类方法的场景。类方法是需要类本身而不是类的实例来执行的方法。您可以通过使用@classmethod 装饰器装饰方法来设计类方法。让我们看看下面的代码。

蟒蛇3

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())
输出
Apple Red:  red
Apple Yellow:  red
Apple Green:  red

在上面的代码中,我们设计了一个名为Apple的类,它具有颜色作为属性。除此之外,我们还使用装饰器@classmethod声明了一个名为classapple的类方法。 classapple方法的功能是返回苹果的颜色。但是,您可以注意到,即使将苹果的颜色设置为黄色和绿色,对象也会返回默认颜色红色。使用类工厂可以克服此限制。

让我们看看下面的代码,它定义了一个名为 create_Apple_subclass 的类工厂。这里我们将创建 Apple 的子类 subApple 来设置颜色。最后,类工厂返回子类。

蟒蛇3

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())
输出
Apple Color:  Yellow
Apple Color:  Green

概括

类工厂是强大的设计模式,可确保动态类创建过程可读、有组织和可重用。而且,类工厂也允许基于发送给函数的参数进行属性切换。