如何在 Python 中实现多重构造函数:一种整洁且符合 Python 风格的方法

Python 不支持显式的多重构造函数,但仍然有一些方法可以实现这一功能。

我们使用 Python 内置的 init 方法来定义类的构造函数。它决定了创建类对象时构造函数执行什么操作。

如果为同一个类编写了多个 init 方法,那么最新的一个会覆盖之前所有的构造函数,其原因在于 Python 将类中的所有函数名作为键(key)存储在字典中,因此当定义一个同名的新函数时,键保持不变,但值(函数体)会被新函数覆盖。

> 前置知识构造函数, @classmethod 装饰器

当在一个类中定义多个 init 方法时会发生什么

一个类中只能有一个 <a href="https://www.geeksforgeeks.org/python/init-in-python/">init 方法。

如果我们创建多个 init 方法,Python 将只考虑最新的那个 init 方法。

注意: 新的 init 方法会覆盖之前的 init 方法。
示例:

class example:

    def __init__(self):
        print("One")

    def __init__(self):
        print("Two")

    def __init__(self):
        print("Three")

e = example()

输出

Three

正如大家在上面的示例中看到的,如果我们尝试创建多个 init 方法,最新的 init 方法会覆盖之前所有的 init 方法。

为什么需要多重构造函数

当我们必须在对 Python 类 进行实例化时执行不同的操作时,就需要多重 构造函数

当类必须针对不同的参数执行不同的操作时,这非常有用。

如何在 Python 中实现多重构造函数?

我们可以通过以下三种方式使类构造函数表现出 多态性

  • 基于参数重载构造函数。
  • init 中调用方法。
  • 使用 @classmethod 装饰器。

让我们通过示例来看看如何以一种 整洁且符合 Python 风格的方式 实现多重构造函数。

基于参数重载构造函数

构造函数重载 是通过检查传递的参数的条件并执行所需的操作来完成的。例如,考虑向一个 sample 类传递参数:

  • 如果参数是 int(整数),结果的答案应该是该数字的平方。
  • 如果参数是 String(字符串),答案应该是 "Hello!!"+string
  • 如果参数的 长度大于 1,则将参数之和存储为答案。

示例:

class sample:

    # constructor overloading
    # based on args
    def __init__(self, *args):

        # if args are more than 1
        # sum of args
        if len(args) > 1:
            self.ans = 0
            for i in args:
                self.ans += i

        # if arg is an integer
        # square the arg
        elif isinstance(args[0], int):
            self.ans = args[0]*args[0]

        # if arg is string
        # Print with hello
        elif isinstance(args[0], str):
            self.ans = "Hello! "+args[0]+"."

s1 = sample(1, 2, 3, 4, 5)
print("Sum of list :", s1.ans)

s2 = sample(5)
print("Square of int :", s2.ans)

s3 = sample("GeeksforGeeks")
print("String :", s3.ans)

输出

Sum of list : 15
Square of int : 25
String : Hello! GeeksforGeeks.

在上面的代码中,实例变量是 ans,但它的值根据参数的不同而不同。

由于类的参数数量可变,因此使用了 *args,它是一个包含传递参数的元组,可以通过索引访问。

在 int 和 string 的情况下,只传递一个参数,因此作为 args[0] 访问(元组中唯一的元素)。

init 中调用方法

一个类可以有一个构造函数 init,它在创建类的实例时执行任何操作。

我们可以让这个构造函数调用不同的函数,这些函数根据传递的参数执行不同的操作。现在考虑一个例子:

  • 如果传递的参数数量为 2,则计算表达式 x = a^2 – b^2
  • 如果传递的参数数量为 3,则计算表达式 y = a^2 + b^2 – c
  • 如果传递了 超过 3 个参数,则 将平方求和,并除以 传递参数中的最大值

示例:

class calc:

    # constructor
    def __init__(self, *args):
        
        # Assigning all the arguments to the class attributes
        self.args = args
        
        # checking the conditions
        if len(args) == 2:
            self.ans = self.two_arg()
            
        elif len(args) == 3:
            self.ans = self.three_arg()
            
        elif len(args) > 3:
            self.ans = self.more_than_three_arg()
    
    def two_arg(self):
        # returns the difference of squares
        return self.args[0]**2 - self.args[1]**2
    
    def three_arg(self):
        # returns sum of squares - c
        return self.args[0]**2 + self.args[1]**2 - self.args[2]
    
    def more_than_three_arg(self):
        # sum of squares / max arg
        sum_sq = 0
        for i in self.args:
            sum_sq += i**2
        return sum_sq / max(self.args)

 
# Driver Code
obj1 = calc(1, 2)
print("Result for two args :", obj1.ans)

obj2 = calc(1, 2, 3)
print("Result for three args :", obj2.ans)

obj3 = calc(1, 2, 3, 4, 5)
print("Result for more than three args :", obj3.ans)

输出

Result for two args : -3
Result for three args : 2
Result for more than three args : 11.0

在上面的示例中,根据传递的参数数量,我们使用了不同的方法来计算属性 ans 的值。

使用 @classmethod 装饰器

这是一种非常整洁且 Python 风格的方式来处理多重构造函数。为了让类表现得像有多个构造函数一样,我们可以使用类方法。

@classmethod 装饰器用于创建返回类实例的工厂方法。这就像一个构造函数重载。我们可以通过为不同的任务创建不同的类方法来实现这一点。

例如:

  • 方法 1: 创建一个接受字符串的构造函数,该字符串以空格分隔。它必须返回一个对象,其中包含字符串的每一行作为类的属性。
  • 方法 2: 它应该能够创建一个将对象复制到新对象的构造函数。

示例:

class sample:

    # default constructor
    def __init__(self, *args):
        
        # assigning attributes
        for i in args:
            setattr(self, i, i)
        
    # class method for constructor overloading
    # accepts a string and creates a list of arguments
    @classmethod
    def from_string(cls, string):
        
        # converting the string to list of attributes
        args = string.split(‘ ‘)
        
        # returning the class with new attributes
        return cls(*args)
    
    # class method for copying one object to another
    @classmethod
    def copy(cls, instance):
        
        # copying the attributes of the old object to new
        new_obj = cls(*instance.__dict__.keys())
        
        # return new object
        return new_obj


# Driver Code
obj = sample("Attribute1", "Attribute2", "Attribute3")
print("Old Object attributes :", obj.__dict__.keys())

# copying the old object to new one
new_obj = sample.copy(obj)
print("New Object attributes :", new_obj.__dict__.keys())

# using from_string method
new_from_str = sample.from_string("Attribute4 Attribute5")
print("New Object from string :", new_from_str.__dict__.keys())

输出

Old Object attributes : dict_keys([‘Attribute1‘, ‘Attribute2‘, ‘Attribute3‘])
New Object attributes : dict_keys([‘Attribute1‘, ‘Attribute2‘, ‘Attribute3‘])
New Object from string : dict_keys([‘Attribute4‘, ‘Attribute5‘])

正如我们所见,类方法 INLINECODE283bf832 接受一个字符串,对其进行处理,并使用 INLINECODEa45d3bc7 返回类 sample 的新实例。

方法 copy 接受一个对象,并使用其键来创建新对象。

这是创建多个构造函数的最 Pythonic(符合 Python 风格)的方式,因为它保持了代码的整洁和可读性。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/22471.html
点赞
0.00 平均评分 (0% 分数) - 0