调用super().__ init __(** kwargs)和多重继承?

时间:2018-05-27 07:56:47

标签: 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 = 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

在第二种方法中我做错了什么?我怎么能在这里正确使用** kwargs和super?

编辑:

这是我一直关注的书中的一个例子的截图:

enter image description here

我在第二个例子中使用** kwargs和super之间的区别是什么?

这也是同一本书和章节的综合案例研究。这适用于我,我理解它是如何工作的,但我似乎无法将其翻译成我自己的工作。

https://pastebin.com/NYGJfMik

2 个答案:

答案 0 :(得分:4)

你在这里遇到的问题并不是特定于超级但对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')

有两个明显的问题:__init__函数传递的参数多于预期,而__init__函数的主体是kwargs的引用,它没有在任何地方定义。虽然在这里理解**kwargs(及其兄弟*args)足以解决这里的问题,而且**kwargs非常有用。让我们首先看一下super有用的原因。让我们想象一下,我们用一些不错的帮助方法在子进程周围写一些包装器(这个架构可能不是最适合这个问题的,但是只看到有继承的动物也没有超级帮助。多重继承是一种非常罕见的情况,所以它&# 39;很难想出不是动物,GameEntities或GUIwidgets的好例子:

class Process:
    def __init__(self, exe):
        self.exe = exe
        self.run()

class DownloadExecutableBeforeProcess(Process):
    def __init__(self, exe):
        self.download_exe(exe)
        Process.__init__(self, exe)

这里我们正在进行继承,我们甚至不需要使用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)

如果我们按照DownloadAndCheck的初始化,我们会看到Process.__init__被调用两次,一次通过DownloadExecutableBefore.__init__,一次通过AuthenticationCheckerProcess.__init__!所以我们要包装的过程也会运行两次,这不是我们想要的。在这个例子中,我们可以通过不在进程的init中调用self.run()来轻松解决这个问题,但在现实世界中,这并不像这里那样容易解决。在这种情况下,调用Process.__init__似乎是错误的。我们能以某种方式解决这个问题吗?

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解决了这个问题,只会拨打Process.__init__一次。它还将处理函数运行的顺序,但这不是一个大问题。我们仍有问题:use_sha=False将传递给所有初始值设定项,但只有一个实际需要它。我们实际上只能将变量传递给只需要它的函数(因为确定这将是一场噩梦),但我们可以教其他__init__来忽略keywoard:

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().__init__(exe, use_sha=False)调用将成功,每个初始化程序只接受它理解的键盘,并简单地将其他键盘向下传递。

因此,如果你有多重继承并使用不同的(keywoard)参数super和kwargs可以解决你的问题。但是超级和多重继承很复杂,特别是如果你有比这里更多的继承层。有时函数应该是calles的顺序甚至没有定义(然后python应该抛出一个错误,参见例如explenation of change of MRO algorithm)。 Mixins甚至可能需要super().__init__()电话,尽管他们甚至不会从任何课程继承。总而言之,如果你使用多重继承,你会在代码中获得很多复杂性,所以如果你真的不需要它,那么通常更好地考虑其他方法来模拟你的问题。

答案 1 :(得分:-1)

这应该有效

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'

bob.get_rate('$12')
My hourly rate is $12