Python 调用super()?
我正在努力学习和理解如何在Python中使用super,我一直在学习《Python从新手到专家之旅》一书,虽然我觉得我理解这个概念,但在我自己的代码中执行super时遇到了问题 例如,此方法适用于我:Python 调用super()?,python,python-3.x,multiple-inheritance,super,Python,Python 3.x,Multiple Inheritance,Super,我正在努力学习和理解如何在Python中使用super,我一直在学习《Python从新手到专家之旅》一书,虽然我觉得我理解这个概念,但在我自己的代码中执行super时遇到了问题 例如,此方法适用于我: class Employee: def __init__(self, firstname, lastname, age, sex, dob): self.firstname = firstname self.lastname = lastna
class Employee:
def __init__(self, firstname, lastname, age, sex, dob):
self.firstname = firstname
self.lastname = lastname
self.age = age
self.sex = sex
self.dob = dob
self.all_staff.append(self)
class Hourly(Employee):
def __init__(self, firstname, lastname, age, sex, dob, rate, hours):
self.rate = rate
self.hours = hours
super().__init__(firstname, lastname, age, sex, dob)
def __str__(self):
return "{} {}\nAge: {}\nSex: {}\nDOB: {}\n".format(self.firstname, self.lastname, self.age,
self.sex, self.dob)
def get_rate(self):
print('The hourly rate of {} is {} '.format(self.firstname, self.rate))
hourlystaff1 = Hourly('Bob', 'Foo', '23', 'M', '12/1/1980', '$15', '30')
print(hourlystaff1)
print(hourlystaff1.get_rate())
返回以下内容:
Bob Foo
Age: 23
Sex: M
DOB: 12/1/1980
The hourly rate of Bob is $15
None
这正是我所期望的(我不确定为什么“无”也会被返回,也许有人可以解释一下?)
然后我想用super试试这个,但是用**kwargs,比如:
class Employee:
def __init__(self, firstname='', lastname='', age='', dob='', **kwargs):
super().__init__(**kwargs)
self.firstname = firstname
self.lastname = lastname
self.age = age
self.dob = dob
class Hourly(Employee):
def __init__(self, rate=''):
self.rate = rate
super().__init__(**kwargs)
def __str__(self):
return "{} {}\nAge: {}\nSex: {}".format(self.firstname, self.lastname, self.age,
self.sex, self.dob, self.rate)
def get_rate(self):
print('The hourly rate of {} is {} '.format(self.firstname, self.rate))
bob = Hourly('Bob', 'Bar', '23', '12/1/2019')
bob.get_rate('$12')
返回此错误:
File "staff_b.py", line 33, in <module>
bob = Hourly('Bob', 'Bar', '23', '12/1/2019')
TypeError: __init__() takes from 1 to 2 positional arguments but 5 were given
文件“staff_b.py”,第33行,在
bob=每小时('bob'、'Bar'、'23'、'12/1/2019')
TypeError:\uuuu init\uuuuu()接受1到2个位置参数,但给出了5个
在第二种方法中,我做错了什么?在这里如何正确使用**kwargs和super
编辑:
这是我一直在关注的书中的一个示例的屏幕截图:
Bob Foo
Age: 23
Sex: M
DOB: 12/1/1980
The hourly rate of Bob is $15
None
在我的第二个示例中,我使用**kwargs和super的方式有什么不同
这也是同一本书和同一章的综合案例研究。这对我来说是可行的,我理解它是如何工作的,但我似乎无法将其转化为我自己的工作
这应该行得通
class Employee:
def __init__(self, firstname='', lastname='', age='', dob=''):
self.firstname = firstname
self.lastname = lastname
self.age = age
self.dob = dob
那你有儿童课
class Hourly2(Employee):
def __init__(self,*args, **kwargs):
super(Hourly2,self).__init__(*args, **kwargs)
def get_rate(self,rate=None):
self.data=rate
print ('My hourly rate is {}'.format(self.data))
现在,让我们举个例子
bob = Hourly2('Bob', 'Bar', '23', '12/1/2019')
我们可以检查属性
dir(bob)
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'age',
'dob',
'firstname',
'get_rate',
'lastname']
最后
bob.age
'23'
及
这里的问题并不是针对super,而是针对kwargs。如果我们扔掉大部分代码并删除super,它看起来如下:
class Hourly(Employee):
def __init__(self, rate=''):
self.rate = rate
some_crazy_function(**kwargs)
hourlystaff1 = Hourly('Bob', 'Foo', '23', 'M', '12/1/1980', '$15', '30')
有两个明显的问题:\uuuuu init\uuuu
函数传递的参数比预期的要多,并且在\uuuuuuu init\uuuu
函数的主体中引用了kwargs
,该函数在任何地方都没有定义。在这里,理解**kwargs
(及其兄弟*args
)就足以解决问题,super和**kwargs
一起非常有用。让我们先看看为什么super
很有用。让我们想象一下,我们用一些很好的助手方法围绕子流程编写一些包装器(架构可能不是最适合解决这个问题的,但只有见过具有继承性的动物也没有太大帮助。多重继承非常罕见,因此很难找到不是动物、游戏实体或guiwidget的好例子):
在这里,我们正在进行继承,甚至不需要使用super-我们可以显式地使用超类的名称并具有我们想要的行为。我们可以在这里重写为使用super
,但它不会改变行为。如果您只从一个类继承,则不需要严格地使用super
,尽管它可以帮助您不要重复从中继承的类名。让我们添加到我们的类hirarchy,并包括从多个类中继承:
class AuthenticationCheckerProcess(Process):
def __init__(self, exe, use_sha=True):
self.check_if_authorized(exe, use_sha)
Process.__init__(self, exe)
class DownloadAndCheck(DownloadExecutableBefore, AuthenticationCheckerProcess):
def __init__(self, exe):
DownloadExecutableBefore.__init__(exe)
AuthenticationCheckerProcess.__init__(exe, use_sha=False)
如果我们按照download的init并检查我们会看到进程。我们要包装的进程也会被调用两次,一次通过DownloadExecutableBefore。一次通过和一次通过AuthenticationChecker进程。因此我们要包装的进程也会运行两次,这不是我们想要的我们可以通过在进程初始化时不调用self.run()
轻松解决此问题,但在现实世界中,这并不总是像这里这样容易解决。在这种情况下,调用process.\uuuu init\uuuu
似乎是错误的。我们能以某种方式解决此问题吗
class DownloadAndCheck(DownloadExecutableBefore, AuthenticationCheckerProcess):
def __init__(self, exe):
super().__init__(exe, use_sha=False)
# also replace the Process.__init__ cals in the other classes with super
super
修复了这个问题,只调用进程一次。它还将负责函数的运行顺序,但这不是一个大问题。我们仍然有一个问题:use\u sha=False
将传递给所有初始化器,但实际上只有一个需要它。我们不能只传递该变量仅适用于需要它的函数(因为找到它将是一场噩梦),但我们可以教其他\uuuu init\uuuu
s忽略键盘:
class Process:
def __init__(self, exe, **kwargs):
# accept arbitrary keywoards but ignore everything but exe
# also put **kwargs in all other initializers
self.exe = exe
self.run()
class DownloadExecutableBeforeProcess(Process):
def __init__(self, exe, **kwargs):
self.download_exe(exe)
# pass the keywoards into super so that other __init__s can use them
Process.__init__(self, exe, **kwargs)
现在,super()。\uuuu init\uuuu(exe,use\u sha=False)
调用将成功,每个初始值设定项只接受它理解的键盘,并简单地向下传递其他键盘
因此,如果您有多个继承并使用不同的(keywoard)参数,super和kwargs可以解决您的问题。但是super和multiple继承非常复杂,特别是如果您的继承层比这里多的话。有时甚至没有定义调用函数的顺序(然后python应该抛出一个错误,请参见示例。)mixin甚至可能需要一个super()
调用,尽管它们甚至不从任何类继承。总之,如果使用多重继承,代码会变得非常复杂,因此如果您真的不需要它,通常最好考虑其他方法来建模您的问题。至于None
,这是因为get\u rate
方法不会返回任何结果参见。至于**kwargs
:你把它们放错地方了。它们应该在每小时使用一次。
方法。而员工不应该调用super()。
或super()
或任何类似的内容。从员工中删除它们,并将它们添加到小时
:def\uuuu init\uuuuu(self,rate='',**kwargs):
啊,这是因为您将它们作为位置参数传递,而不是关键字参数。您可以将所有的**kwargs
更改为*args,**kwargs
。但是请注意,您将'Bob'
作为rate
参数的值传递,所以也许您应该使用关键字参数来避免犯类似的错误那。啊,我想我明白你在说什么。书中的类是为多重继承而设计的。(你可以看到,Friend
同时继承了Contact
和AddressHolder
)你可能会发现我的答案很有用。我不确定我是否应该
class Process:
def __init__(self, exe, **kwargs):
# accept arbitrary keywoards but ignore everything but exe
# also put **kwargs in all other initializers
self.exe = exe
self.run()
class DownloadExecutableBeforeProcess(Process):
def __init__(self, exe, **kwargs):
self.download_exe(exe)
# pass the keywoards into super so that other __init__s can use them
Process.__init__(self, exe, **kwargs)