📜  在Python中拥有多个构造函数的干净的 Pythonic 方式是什么?

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

在Python中拥有多个构造函数的干净的 Pythonic 方式是什么?

先决条件 -构造函数 @classmethod 装饰器

Python不支持显式的多重构造函数,但有一些方法可以实现多重构造函数。如果为同一个类编写了多个__init__方法,则最新的方法会覆盖之前的所有构造函数。看看下面的例子。

Python3
class example:
  
    def __init__(self):
        print("One")
  
    def __init__(self):
        print("Two")
  
    def __init__(self):
        print("Three")
  
  
e = example()


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


Python3
class eval_equations:
  
  # single constructor to call other methods
    def __init__(self, *inp):
  
        # when 2 arguments are passed
        if len(inp) == 2:
            self.ans = self.eq2(inp)
  
        # when 3 arguments are passed
        elif len(inp) == 3:
            self.ans = self.eq1(inp)
  
        # when more than 3 arguments are passed
        else:
            self.ans = self.eq3(inp)
  
    def eq1(self, args):
        x = (args[0]*args[0])+(args[1]*args[1])-args[2]
        return x
  
    def eq2(self, args):
        y = (args[0]*args[0])-(args[1]*args[1])
        return y
  
    def eq3(self, args):
        temp = 0
        for i in range(0, len(args)):
            temp += args[i]*args[i]
          
        temp = temp/max(args)
        z = temp
        return z
  
  
inp1 = eval_equations(1, 2)
inp2 = eval_equations(1, 2, 3)
inp3 = eval_equations(1, 2, 3, 4, 5)
  
print("equation 2 :", inp1.ans)
print("equation 1 :", inp2.ans)
print("equation 3 :", inp3.ans)


Python3
class eval_equations:
  
    # basic constructor
    def __init__(self, a):
        self.ans = a
  
    # expression 1
    @classmethod
    def eq1(cls, args):
        
      # create an object for the class to return
        x = cls((args[0]*args[0])+(args[1]*args[1])-args[2])
        return x
  
    # expression 2
    @classmethod
    def eq2(cls, args):
        y = cls((args[0]*args[0])-(args[1]*args[1]))
        return y
  
    # expression 3
    @classmethod
    def eq3(cls, args):
        temp = 0
  
        # square of each element
        for i in range(0, len(args)):
            temp += args[i]*args[i]
  
        temp = temp/max(args)
        z = cls(temp)
        return z
  
  
li = [[1, 2], [1, 2, 3], [1, 2, 3, 4, 5]]
i = 0
  
# loop to get input three times
while i < 3:
  
    inp = li[i]
  
    # no.of.arguments = 2
    if len(inp) == 2:
        p = eval_equations.eq2(inp)
        print("equation 2 :", p.ans)
  
    # no.of.arguments = 3
    elif len(inp) == 3:
        p = eval_equations.eq1(inp)
        print("equation 1 :", p.ans)
  
    # More than three arguments
    else:
        p = eval_equations.eq3(inp)
        print("equation 3 :", p.ans)
  
    #increment loop        
    i += 1


输出
Three

需要多个构造函数

当必须对类的实例化执行不同的操作时,需要多个构造函数。当类必须对不同的参数执行不同的操作时,这很有用。可以通过下面列出的三种方式使类构造函数表现出多态性。

  1. 基于参数重载构造函数。
  2. __init__调用方法。
  3. 使用@classmethod装饰器。

本文通过示例解释了如何以干净和 Pythonic 的方式拥有多个构造函数。

基于参数重载构造函数

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

  • 如果参数是int ,则数字的平方应该是答案。
  • 如果参数是String ,则答案应该是“Hello!!”+ 字符串。
  • 如果参数的长度大于 1,则参数的总和应存储为答案。

蟒蛇3

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 和字符串的情况下,只传递一个参数,因此作为 args[0] (元组中唯一的元素)访问。

从 __init__ 调用方法

一个类可以有一个构造函数 __init__ ,它可以在创建类的实例时执行任何操作。这个构造函数可以用于不同的函数,这些函数根据传递的参数执行不同的操作。现在考虑一个例子:

  • 如果传递的参数数量为 2,则计算表达式x = a 2 -b 2
  • 如果传递的参数数量为 3,则计算表达式y = a 2 +b 2 -c。
  • 如果 传递了 3 个以上的参数,然后将平方相加,除以传递的参数中的最大值。

蟒蛇3

class eval_equations:
  
  # single constructor to call other methods
    def __init__(self, *inp):
  
        # when 2 arguments are passed
        if len(inp) == 2:
            self.ans = self.eq2(inp)
  
        # when 3 arguments are passed
        elif len(inp) == 3:
            self.ans = self.eq1(inp)
  
        # when more than 3 arguments are passed
        else:
            self.ans = self.eq3(inp)
  
    def eq1(self, args):
        x = (args[0]*args[0])+(args[1]*args[1])-args[2]
        return x
  
    def eq2(self, args):
        y = (args[0]*args[0])-(args[1]*args[1])
        return y
  
    def eq3(self, args):
        temp = 0
        for i in range(0, len(args)):
            temp += args[i]*args[i]
          
        temp = temp/max(args)
        z = temp
        return z
  
  
inp1 = eval_equations(1, 2)
inp2 = eval_equations(1, 2, 3)
inp3 = eval_equations(1, 2, 3, 4, 5)
  
print("equation 2 :", inp1.ans)
print("equation 1 :", inp2.ans)
print("equation 3 :", inp3.ans)
输出
equation 2 : -3
equation 1 : 2
equation 3 : 11.0

在上面的例子中,要评估的方程写在不同的实例方法上,并返回答案。构造函数调用适当的方法并对不同的参数采取不同的行动。

表达式计算如下:

使用@classmethod 装饰器

此装饰器允许在不实例化类的情况下访问函数。类的实例和类本身都可以访问这些函数。声明为classmethod的方法的第一个参数是cls,就像self 的实例方法。这里cls指的是类本身。这被证明对于在Python中使用多个构造函数非常有帮助,并且是考虑到上述方法的更 Pythonic 的方法。考虑上面使用的相同示例。根据输入的数量评估不同的表达式。

蟒蛇3

class eval_equations:
  
    # basic constructor
    def __init__(self, a):
        self.ans = a
  
    # expression 1
    @classmethod
    def eq1(cls, args):
        
      # create an object for the class to return
        x = cls((args[0]*args[0])+(args[1]*args[1])-args[2])
        return x
  
    # expression 2
    @classmethod
    def eq2(cls, args):
        y = cls((args[0]*args[0])-(args[1]*args[1]))
        return y
  
    # expression 3
    @classmethod
    def eq3(cls, args):
        temp = 0
  
        # square of each element
        for i in range(0, len(args)):
            temp += args[i]*args[i]
  
        temp = temp/max(args)
        z = cls(temp)
        return z
  
  
li = [[1, 2], [1, 2, 3], [1, 2, 3, 4, 5]]
i = 0
  
# loop to get input three times
while i < 3:
  
    inp = li[i]
  
    # no.of.arguments = 2
    if len(inp) == 2:
        p = eval_equations.eq2(inp)
        print("equation 2 :", p.ans)
  
    # no.of.arguments = 3
    elif len(inp) == 3:
        p = eval_equations.eq1(inp)
        print("equation 1 :", p.ans)
  
    # More than three arguments
    else:
        p = eval_equations.eq3(inp)
        print("equation 3 :", p.ans)
  
    #increment loop        
    i += 1
输出
equation 2 : -3
equation 1 : 2
equation 3 : 11.0

在上面的例子中,对象的实例不是最初创建的。使用@classmethod装饰器定义了用于评估各种表达式的类方法。现在可以使用类名调用它们,并在评估表达式后在该类方法中创建对象。实例变量为传递的不同数量的参数保存不同的答案。