2013-07-05 3 views
0

Я пытаюсь изучить наследование в python. Я пишу класс «Курс» как суперкласс класса «AdvacedCourse», как показано ниже.TypeError Inheritance в Python

class Course(object): 
    def __init__(self, crsName ="python", duration=45): 
     self.crsName = crsName 
     self.duration = 25 

И суб класс:

import Course 
class AdvancedCourse (Course):  
    def __init__(self, crsName ="python", duration=45): 
     self.crsName = "java" 
     self.duration = 25 

Но я застрял на ошибку:

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

Любые предложения?

ответ

3

Это проблема с импортом, а не наследованием. Course - это модуль: вам необходимо наследовать от Course.Course. (В Python мы обычно называем модули в нижнем регистре, хотя).

+3

Самое смешное, насколько сложно описать, почему вы получаете именно эту ошибку. Путем использования «курса» в качестве базового класса вы пытаетесь использовать «модуль» в качестве метакласса, что означает вместо вызова типа («AdvancedCourse», ['Course'], {}) 'you're вызывая 'module ('AdvancedCourse', ['Course'], {})', но 'module' принимает только аргументы' name' и 'doc'. – abarnert

+0

@abarnert, +1 для вас - ответьте на него. Я думал, что это понятно из модуля .__ init __() принимает не более 2 аргументов (3 заданных) ', но я уже забыл о времени, когда трассировка Python была для меня загадкой. Определенно ваш смысл стоит упомянуть. – ElmoVanKielmo

1

Я предполагаю, что класс Course находится в другом модуле Course.py.
Затем вы должны импортировать его с помощью from Course import Course. И @ Даниэль прав - у вас должен быть модуль в файле course.py (строчный), а оператор импорта будет from course import Course.

1

Примечание: Я только дал ответ, потому что 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__.

+0

Хорошо Объяснение. – kona