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 风格)的方式,因为它保持了代码的整洁和可读性。