Примечание: Я только дал ответ, потому что ElmoVanKielmo предложил его. Это определенно не должно быть принятым ответом, поскольку это будет только путать с новичками ... но, возможно, это будет интересно другим.
Как объясняет Даниэль Роземан, import Course
означает, что Course
является модулем, а Course.Course
- это класс, который вы хотите.
Итак, что происходит, когда вы пытаетесь наследовать модуль?
В Python классы являются объектами, как и все остальное. Тип класса (который вы можете увидеть при печати type(AdvancedCourse)
) обычно type
, но вы можете указать другой тип, установив метакласс. Когда вы наследуете суперкласс, если вы не укажете метакласс, вы получите метакласс класса суперкласса. Итак, когда вы делаете это:
import Course
class AdvancedCourse(Course):
... Вы говорите, что ваш метаклассом является type(Course)
, то есть, module
*
Подобно тому, как создание экземпляра означает вызов к классу __init__
, создавая. class означает вызов метакласса __init__
. Аргументы, кроме self
(это класс здесь, а не экземпляр, конечно, и поэтому обычно называются cls
вместо self
) - это имя класса, список базовых классов и словарь методов и других атрибутов. Таким образом, это определение:
class AdvancedCourse(Course):
pass
... пытается инициализировать module
объект с помощью вызова module.__init__(cls, 'AdvancedCourse', (Course,), {}
) **
, конечно, модули также простые объекты, поэтому у них есть __init__
тоже, но их аргументы просто. self
, имя и docstring. Итак, вы передаете слишком много аргументов.
На самом деле вам просто повезло; если module
и type
оказались в том же количестве аргументов в своем конструкторе, у вас получилось бы что-то очень странное, которое каким-то образом походило бы на класс, но не на других, вызывающих всевозможные тонкие ошибки.
Если вы хотите, чтобы играть с этим в интерактивном интерпретаторе, попробуйте следующее:
>>> class meta(type):
... def __init__(self, name, bases, d):
... print('{}\n{}\n{}\n{}\n'.format(self, name, bases, d))
... super(meta, self).__init__(name, bases, d)
>>> class Silly(metaclass=meta):
... __metaclass__=meta
<class '__main__.Silly'>
Silly
()
{'__module__': '__main__', '__qualname__': 'Silly', '__metaclass__': <class '__main__.meta'>}
>>> class Sillier(Silly):
... pass
<class '__main__.Sillier'>
Sillier
(<class '__main__.Silly'>,)
{'__module__': '__main__', '__qualname__': 'Sillier'}
В Python 2.x, вы не хотите, чтобы metaclass=meta
в заголовке класса; вы можете просто положить object
. В 3.x вам не нужен __metaclass__=meta
в теле; вы можете просто поставить pass
.
* module
это один из тех «скрытых» видов, не доступных по имени в встроенные команды, но вы можете получить на него как types.ModuleType
, или просто импортировать что-то и с помощью type(Course)
.
** На самом деле, даже пустой класс имеет несколько членов в своем словаре. Например, в Python 3.3 всегда есть атрибут __module__
и атрибут __qualname__
.
Самое смешное, насколько сложно описать, почему вы получаете именно эту ошибку. Путем использования «курса» в качестве базового класса вы пытаетесь использовать «модуль» в качестве метакласса, что означает вместо вызова типа («AdvancedCourse», ['Course'], {}) 'you're вызывая 'module ('AdvancedCourse', ['Course'], {})', но 'module' принимает только аргументы' name' и 'doc'. – abarnert
@abarnert, +1 для вас - ответьте на него. Я думал, что это понятно из модуля .__ init __() принимает не более 2 аргументов (3 заданных) ', но я уже забыл о времени, когда трассировка Python была для меня загадкой. Определенно ваш смысл стоит упомянуть. – ElmoVanKielmo