在python中用父类方法重写uuu init uuuuu
我希望执行以下操作(在Python 3.7中): 基本上,我想用父类的工厂类方法覆盖子类的在python中用父类方法重写uuu init uuuuu,python,inheritance,constructor,class-method,Python,Inheritance,Constructor,Class Method,我希望执行以下操作(在Python 3.7中): 基本上,我想用父类的工厂类方法覆盖子类的\uuuu init\uuu方法。但是,编写的代码不起作用,并引发: TypeError: __init__() takes 1 positional argument but 3 were given 我认为这意味着super()。有两条腿('Human')作为cls变量传递Human 1) 为什么这不符合书面要求?我假设super()将返回超类的代理实例,因此cls将是Animal对吗 2) 即使是这
\uuuu init\uuu
方法。但是,编写的代码不起作用,并引发:
TypeError: __init__() takes 1 positional argument but 3 were given
我认为这意味着super()。有两条腿('Human')
作为cls
变量传递Human
1) 为什么这不符合书面要求?我假设super()
将返回超类的代理实例,因此cls
将是Animal
对吗
2) 即使是这种情况,我也不认为这段代码达到了我想要的效果,因为classmethod返回了Animal
的一个实例,但我只想用classmethod的方法初始化Human
,有什么方法可以达到我想要的行为吗
我希望这不是一个很明显的问题,我发现on
super()
有些混乱。调用super
得到的代理对象仅用于定位要调用的具有两条腿的方法(由于您没有在Human
中覆盖它,您可以使用self.with_两条腿
获得相同的结果)
如前所述,您的具有两条腿的替代构造函数不起作用,因为Human
类具有不同的构造函数签名,从而打破了传统的构造函数。即使您可以让代码调用Animal
来构建您的实例,您也会遇到问题,因为您最终会得到一个Animal
实例,而没有t aHuman
one(因此Human
中的其他方法,如果您编写了一些,将不可用)
请注意,这种情况并不少见,许多Python子类的构造函数签名与其父类不同。但这确实意味着您不能自由地使用一个类来代替另一个类,就像尝试构造实例的classmethod
一样。您需要避免这些情况
在这种情况下,最好为Animal
构造函数的legs
参数使用一个默认值。如果没有传递替代数字,它可以默认为2
legs。这样,您就不需要类方法
,并且在重写\uuu init\uuu
时也不会遇到问题:
class Animal:
def __init__(self, name, legs=2): # legs is now optional, defaults to 2
self.legs = legs
print(name)
class Human(Animal):
def __init__(self):
super().__init__('Human')
john = Human()
通过调用super
获得的代理对象仅用于定位要调用的with_two_legs
方法(由于您没有在Human
中重写它,因此您可以使用self.with_two_legs
获得相同的结果)
如前所述,您的具有两条腿的替代构造函数不起作用,因为Human
类具有不同的构造函数签名,从而打破了传统的构造函数。即使您可以让代码调用Animal
来构建您的实例,您也会遇到问题,因为您最终会得到一个Animal
实例,而没有t aHuman
one(因此Human
中的其他方法,如果您编写了一些,将不可用)
请注意,这种情况并不少见,许多Python子类的构造函数签名与其父类不同。但这确实意味着您不能自由地使用一个类来代替另一个类,就像尝试构造实例的classmethod
一样。您需要避免这些情况
在这种情况下,最好为Animal
构造函数的legs
参数使用一个默认值。如果没有传递替代数字,它可以默认为2
legs。这样,您就不需要类方法
,并且在重写\uuu init\uuu
时也不会遇到问题:
class Animal:
def __init__(self, name, legs=2): # legs is now optional, defaults to 2
self.legs = legs
print(name)
class Human(Animal):
def __init__(self):
super().__init__('Human')
john = Human()
super()。用两条腿('Human')
实际上用两条腿调用Animal
,但它传递Human
,因为cls
,而不是Animal
super()
使代理对象仅用于协助方法查找,它不会更改传递的内容(它仍然是源于self
或cls
)在这种情况下,super()
甚至没有做任何有用的事情,因为Human
不会用两条腿覆盖,所以:
super().with_two_legs('Human')
表示“在定义它的层次结构中,从上面的第一个类Human
调用,使用两条腿
”,并且:
意思是“在层次结构中以定义它的cls
开头的第一个类上用两条腿调用”。只要动物
下面没有定义它的类,它们就做同样的事情
这意味着您的代码在返回cls(name\u full,2)
时中断,因为cls
仍然是Human
,而您的也是Human.\uuuu init\uuuu
不接受任何超出self
的参数。即使您费尽心思让它工作(例如,通过添加两个您忽略的可选参数),这将导致一个无限循环,如人类。
称为动物。它有两条腿,然后试图构造一个人类
,再次调用人类。
您试图做的不是一个好主意;备用构造函数本质上依赖于类的核心构造函数/初始值设定项。如果您试图创建一个依赖于备用构造函数的核心构造函数/初始值设定项,那么您已经创建了一个循环依赖项
在这种特殊情况下,我建议避免使用替代构造函数,要么显式地始终提供legs
计数,要么使用执行替代构造函数任务的中间TwoLeggedAnimal
类。如果要重用代码,第二个选项只意味着“从name生成name_full的超长代码”可以进入第一个选项中的TwoLeggedAnimal,
cls.with_two_legs('Human')
class Animal:
def __init__(self, name, legs):
self.legs = legs
print(name)
class TwoLeggedAnimal(Animal)
def __init__(self, name):
# extremely long code to generate name_full from name
name_full = name
super().__init__(name_full, 2)
class Human(TwoLeggedAnimal):
def __init__(self):
super().__init__('Human')
class Animal:
def __init__(self, name, legs):
self.legs = legs
print(name)
@staticmethod
def _make_two_legged_name(basename):
# extremely long code to generate name_full from name
return name_full
@classmethod
def with_two_legs(cls, name):
return cls(cls._make_two_legged_name(name), 2)
class Human(Animal):
def __init__(self):
super().__init__(self._make_two_legged_name('Human'), 2)
def __init__(self):
self_template = super().with_two_legs('Human')
# Cheaty way to copy all attributes from self_template to self, assuming no use
# of __slots__
vars(self).update(vars(self_template))
class Animal:
def __new__(cls, name, legs): # Use __new__ instead of __init__
self = super().__new__(cls) # Constructs base object
self.legs = legs
print(name)
return self # Returns initialized object
@classmethod
def with_two_legs(cls, name):
# extremely long code to generate name_full from name
name_full = name
return Animal.__new__(cls, name_full, 2) # Explicitly call Animal's __new__ using correct subclass
class Human(Animal):
def __new__(cls):
return super().with_two_legs('Human') # Return result of alternate constructor