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

我正在努力学习和理解如何在Python中使用super,我一直在学习《Python从新手到专家之旅》一书,虽然我觉得我理解这个概念,但在我自己的代码中执行super时遇到了问题

例如,此方法适用于我:

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)