【问题标题】:Python3 Multiple inheritance TypeError: object.__init__() takes no parametersPython3 多重继承 TypeError: object.__init__() 不带参数
【发布时间】:2017-09-05 10:37:14
【问题描述】:

我正在学习 Python3 中的多重继承。我想知道为什么案例#1 有效,但案例#2 无效。这是我的代码 sn-ps。

class ContactList(list):
    def search(self, name):
        """Return all contacts that contain the search value
        in their name."""
        matching_contacts = []
        for contact in self:
            if name in contact.name:
                matching_contacts.append(contact)
        return matching_contacts


class Contact:
    all_contacts = ContactList()

    def __init__(self, name="", email="", **kwargs):
        super().__init__(**kwargs)
        self.name = name
        self.email = email
        Contact.all_contacts.append(self)
        print("Cotact")


class AddressHolder:
    def __init__(self, street="", city="", state="", code="", **kwargs):
        super().__init__(**kwargs)
        self.street = street
        self.city = city
        self.state = state
        self.code = code
        print("AddressHolder")


class Friend(Contact, AddressHolder):
    # case# 1
    # def __init__(self, phone="", **kwargs):
    #     self.phone = phone
    #     super().__init__(**kwargs)
    #     print("Friend")

    # case# 2
    def __init__(self, **kwargs):
        self.phone = kwargs["phone"]
        super().__init__(**kwargs)
        print("Friend")


if __name__ == "__main__":
    friend = Friend(
        phone="01234567",
        name="My Friend",
        email="myfriend@example.net",
        street="Street",
        city="City",
        state="State",
        code="0123")

这是脚本的输出。如果我在继承“Contact”和“AddressHolder”的“Friend”中仅使用 kwargs(案例#2)作为参数,则 Python 会出错。我已经测试了相同类型的没有继承的构造,除了对象,它工作得很好。

"""
case 1#
$ python contacts.py
AddressHolder
Cotact
Friend
>>> friend.name
'My Friend'
>>> friend.phone
'01234567'
>>>
"""

"""
case 2#
$ python contacts.py
Traceback (most recent call last):
  File "contacts.py", line 55, in <module>
    code="0123")
  File "contacts.py", line 43, in __init__
    super().__init__(**kwargs)
  File "contacts.py", line 16, in __init__
    super().__init__(**kwargs)
  File "contacts.py", line 25, in __init__
    super().__init__(**kwargs)
TypeError: object.__init__() takes no parameters
>>>
"""

【问题讨论】:

    标签: python-3.x typeerror multiple-inheritance keyword-argument


    【解决方案1】:

    我们来看看Friend的方法解析顺序。这将告诉我们构造函数的调用顺序:

    >>> Friend.mro()
    [<class '__main__.Friend'>, <class '__main__.Contact'>, <class '__main__.AddressHolder'>, <class 'object'>]
    

    那么让我们先来看看案例 1。这些是 Friend 构造函数的原始命名参数:

    phone="01234567"
    name="My Friend"
    email="myfriend@example.net"
    street="Street"
    city="City"
    state="State"
    code="0123"
    

    现在,Friend.__init__phone 作为显式参数,然后将其余部分作为关键字参数字典。所以kwargs 如下:

    kwargs = {
        'name': "My Friend",
        'email': "myfriend@example.net",
        'street': "Street",
        'city': "City",
        'state': "State",
        'code': "0123",
    }
    

    接下来,调用Contact.__init__ 接受参数nameemail。这会留下kwargs,如下所示:

    kwargs = {
        'street': "Street",
        'city': "City",
        'state': "State",
        'code': "0123",
    }
    

    接下来,AddressHolder.__init__ 被调用,它接受参数 streetcitystatecode。所以kwargs留下如下:

    kwargs = {}
    

    一本空字典!所以对object.__init__ 的最终调用是在没有传递任何参数的情况下发生的,这很好,因为object 构造函数不接受任何参数。

    现在,我们来看看第二种情况。这里,phone 不是Friend.__init__ 的显式参数,所以它在字典中作为关键字参数传递。在所有后续调用中,流程与上述完全相同,除了 phone 从未从 kwargs 字典中取出。所以最后调用object.__init__kwargs 仍然是这样的:

    kwargs = {
        'phone': "01234567",
    }
    

    这对object.__init__ 来说是个问题,因为它不接受phone 参数(或任何真正的参数)。所以这就是案例二在这里失败的原因:因为在object.__init__之前还有一个关键字参数。

    【讨论】:

    • 感谢@poke 的精彩解释。现在事情对我来说越来越清楚了。由于我的声誉低,无法投票。然而,这个答案无疑改变了我学习 Python 的方式。
    • 请注意,即使像 {} 这样使用空的 kwargs 调用对象的 __init__ 也是不允许的!
    猜你喜欢
    • 2011-07-06
    • 2012-06-26
    • 1970-01-01
    • 1970-01-01
    • 2018-02-09
    • 2011-07-30
    • 2015-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多