当你从模块而不是Python中的类固有时会发生什么?

时间:2016-06-17 08:07:29

标签: python class inheritance module python-internals

我最近遇到了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是一个模块,而不是一个类。所以   你的继承是棘手的。

     

将您的import语句更改为:

from Object import ClassName
     

并将您的班级定义为:

class Visitor(ClassName):
     

     

将您的班级定义更改为:

class Visitor(Object.ClassName):
   etc

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

2 个答案:

答案 0 :(得分:3)

如果在继承列表中放置一个名为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)

答案 1 :(得分:0)

要找出您出错的地方,在这种情况下,您真的不需要查看错误消息,从代码本身可以清楚地了解它。

import foo

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

一旦你得到了它,你试图继承/继承module,其余的并不是那么棘手。

大多数模块都没有定义__init__,这意味着当您尝试访问它时,它只是试图在继承链中找到它(如果您真的对此感兴趣,你可以阅读python继承,mro等,但我怀疑这里没有让你感到困惑的东西。)并找到内置类moduleimport Object;type(Object)import os; type(os) )有一个__init__期望的参数不同于被重写的方法。如果你的方法与上面的参数数量完全相同,那么调试会更加棘手。

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

import os
help(type(os))