2016-06-17 3 views
2

Я недавно натолкнулся this question.Что происходит, когда вы принадлежите модулю вместо класса в Python?

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()) 

I get this error:

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'> 

Your error is happening because Object is a module, not a class. So your inheritance is screwy.

Change your import statement to:

from Object import ClassName 

and your class definition to:

class Visitor(ClassName): 

or

change your class definition to:

class Visitor(Object.ClassName): 
    etc 

Я не очень доволен этим ответом, как я на самом деле не знаю, как я получаю от этого сообщения об ошибке к выводу, что я случайно унаследовать от модуль вместо класса. Мне было интересно, может ли кто-нибудь объяснить, почему эта ошибка происходит и какие именно аргументы даются? Когда интерпретатор python сталкивается с таким кодом: class Employee(Person) что происходит? Что именно означает, что ответчик имеет в виду мое наследство, является отвратительным? Спасибо за любые объяснения или ссылки на ресурсы.

+1

Язык python настолько динамичен, что вы можете передавать любую сущность, которая существует. Только при выполнении этих проблем сообщается о проблемах. Если бы вы передали целочисленную переменную как родительскую, она бы попыталась вызвать init() для int тоже. –

+1

См. [_The Python Tutorial_] (https://docs.python.org/3/tutorial/), [9.5. Наследование] (https://docs.python.org/3/tutorial/classes.html#inheritance). Использование оператора 'import' описано в [6. Модули] (https://docs.python.org/3/tutorial/modules.html). –

ответ

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) 
+0

Спасибо, это именно то, что я искал – user3282276

+1

На самом деле, 'type (BaseClass) (...)' вызывается. Это означает, что 'type (BaseClass) .__ init__' вызывается, если существует' type (BaseClass) .__ new__', который вызывает его. –

0

Чтобы узнать, где вы поступили не так, в этом случае вам не обязательно смотреть сообщение об ошибке, это довольно ясно из самого кода.

import foo

всегда означает, что Foo представляет собой модуль (в отличие от from foo import bar, где bar может быть модулем, класс, функция переменной и так далее). Здесь нам помогают соглашения об именах, если следовать за PEP8, тогда можно легко различать классы и модуль. Код в вашем вопросе не соответствует тому, что явно не подходит для понимания другими.

Как только вы получите это, вы попытались подкласса/наследовать module, все остальное не так сложно.

Большинство модулей не определяют __init__, что означает, что когда вы пытаетесь получить к нему доступ, он просто пытается найти его в цепочке наследования (если вы действительно заинтересованы в этом, вы можете прочитать наследование python, mro и т. д., но я подозреваю, что это не то, что вас смутило.) и находит встроенный класс module, который (do import Object;type(Object) или import os; type(os)) имеет __init__, ожидающий разные аргументы, чем ваш переопределенный метод. Это было бы более сложным для отладки, если ваш метод имеет точно такое же количество аргументов, как указано выше.

Сообщение об ошибке вам не подходит, так как для python нет способа понять, намеренно ли вы хотите переопределить module.__init__ или класс __init__.Попробуйте

import os 
help(type(os)) 
Смежные вопросы