【问题标题】:What happens when you inherent from a module instead of a class in Python?当您从 Python 中的模块而不是类继承时会发生什么?
【发布时间】:2016-10-18 23:33:50
【问题描述】:

我最近遇到了this question

import Object

class Visitor(Object):

    def __init__(self):
        super(Visitor,self).__init__()
    def visit(self, obj):
        pass
    def getIsDone(self):
        return False
    isDone = property(fget =lambda self:self.getIsDone())

我得到这个错误:

TypeError: module.__init__() takes at most 2 arguments (3 given)

及其答案:

class A:pass
print(A)              #outputs <class '__main__.A'>
import urllib
print(urllib)         #outputs <module 'urllib' from '/usr/lib/python3.2/urllib/__init__.py'>

您的错误正在发生,因为 Object 是一个模块,而不是一个类。所以 你的继承权很糟糕。

将您的导入语句更改为:

from Object import ClassName

和你的类定义:

class Visitor(ClassName):

将您的类定义更改为:

class Visitor(Object.ClassName):
   etc

我对这个答案并不满意,因为我不确定如何从该错误消息中得出结论,即我不小心继承自模块而不是类。我想知道是否有人可以详细说明为什么会发生此错误以及给出的论点到底是什么?当 python 解释器遇到这样的代码时: class Employee(Person) 发生了什么?回答者所说的我的继承权到底是什么意思?感谢您对资源的任何解释或参考。

【问题讨论】:

  • python 语言是如此动态,你可以传递任何存在的实体。只有在执行时才会报告问题。如果您将整数变量作为父级传递,它也会尝试为 int 调用 init()。
  • 有关概述,请参阅The Python Tutorial9.5. Inheritanceimport 语句的使用包含在 6. Modules 中。

标签: python class inheritance module python-internals


【解决方案1】:

要找出你哪里出错了,在这种情况下你真的不需要看错误信息,从代码本身就很清楚了。

import foo

总是意味着 foo 是一个模块(与 from foo import bar 相反,bar 可以是模块、类、函数、变量等)。这就是命名约定对我们有帮助的地方,如果遵循PEP8,那么可以很容易地区分类和模块。您问题中的代码没有遵循,这显然不利于其他人理解。

一旦你知道你已经尝试继承/继承module,剩下的就不是那么棘手了。

大多数模块没有定义__init__,这意味着当你尝试访问它时,它只是试图在继承链中找到它(如果你真的对此感兴趣,你可以阅读python继承, mro 等,但我怀疑这不是在这里让您感到困惑的原因。)并找到内置类 module(执行 import Object;type(Object)import os; type(os))有一个 __init__ 期望与您的覆盖方法不同的参数。如果您的方法具有与上述完全相同数量的参数,则调试起来会更加棘手。

错误消息似乎对您没有帮助,因为 python 无法理解您是否有意覆盖 module.__init__ 或某个类的 __init__。试试

import os
help(type(os))

【讨论】:

    【解决方案2】:

    如果您将一个名为BaseClass 的对象放入继承列表中,那么解释器将在内部调用它:

    type(BaseClass).__init__(cls, name_of_subclass, (BaseClass,), dict_of_subclass)
    # or simpler
    type(BaseClass)(name_of_subclass, (BaseClass,), dict_of_subclass)
    

    你可以创建一个虚拟 BaseClass 来测试它

    class Meta(object):
       def __init__(self, name,   base,  subcls):
          print (self, name,   base,  subcls)
    
    Base = Meta('','','')
    
    class Test(Base):
        prop1="hello"
    

    哪个输出:

    <__main__.Meta object at 0x7f7471666bd0>
    <__main__.Meta object at 0x7f7471666c50> Test (<__main__.Meta object at 0x7f7471666bd0>,) {'__module__': '__main__', 'prop1': 'hello'}
    

    回答你的问题:当解释器看到class Employee(Person): pass时,会发生以下情况:

    type(Person).__init__(cls, 'Employee', (Person,), {'__module__': '__main__'})
    

    如果Person 是一个普通类,type(person) 将返回type 本身。然后type.__init__ 将被调用。

    如果Person 是一个模块,type(person) 将返回对象module,它有一个方法__init__。但是这个方法只需要 2 个参数,你会得到一个错误。

    import sys
    type(sys).__init__(sys,2,3,4)
    #Traceback (most recent call last):
    #  File "testClassInheritance.py", line 11, in <module>
    #    type(sys).__init__(sys,2,3,4)
    #TypeError: module.__init__() takes at most 2 arguments (3 given)
    

    【讨论】:

    • 谢谢,这正是我想要的
    • 其实是调用了type(BaseClass)(...)。这意味着如果有 type(BaseClass).__new__ 调用它,就会调用 type(BaseClass).__init__
    猜你喜欢
    • 2013-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-26
    相关资源
    最近更新 更多