0

I am trying to learn inheritance in python. I write class "Course" as super class of class "AdvacedCourse" as shown below.

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

And the sub class is:

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

But I got stuck on an error:

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

Any suggestions?

3 Answers 3

3

This is a problem with importing, not inheritance. Course is the module: you need to inherit from Course.Course. (In Python we usually name modules in lower case, though).

Sign up to request clarification or add additional context in comments.

2 Comments

The funny thing is how hard it is to describe why you get exactly this error. By trying to use Course as a base class, you're trying to use module as a metaclass, which means instead of calling type('AdvancedCourse', ['Course'], {}) you're calling module('AdvancedCourse', ['Course'], {}), but module only takes name and doc arguments.
@abarnert, +1 for you - make an answer from it. I thought it's clear from the module.__init__() takes at most 2 arguments (3 given) but I already forgot the times, when Python traceback was a mystery for me too. Definitely your point is worth to mention.
1

I assume that class Course is in another module Course.py.
Then you should import it with from Course import Course. And @Daniel is right - you should have module in file course.py (lowercase) and import statement will be from course import Course.

Comments

1

Note: I've only made this an answer because ElmoVanKielmo suggested it. It definitely shouldn't be the accepted answer, as it will only be confusing to novices… but maybe it will be interesting to others.

As Daniel Roseman's answer explains, import Course means that Course is a module, and Course.Course is the class you want.

So, what happens when you try to inherit from a module?

In Python, classes are objects, just like anything else. A class's type (which you can see by printing out type(AdvancedCourse)) is usually type, but you can specify a different type by setting a metaclass. When you inherit from a superclass, if you don't specify a metaclass, you get your superclass's metaclass. So, when you do this:

import Course
class AdvancedCourse(Course):

… you're saying that your metaclass is type(Course)—that is, module.*

Just as creating an instance means a call to the class's __init__, creating a class means a call to the metaclass's __init__. The arguments, besides self (which is a class here, not an instance, of course, and therefore usually named cls instead of self) are the class name, the list of base classes, and the dictionary of methods and other attributes. So, this definition:

class AdvancedCourse(Course):
    pass

… tries to initialize a module object by calling module.__init__(cls, 'AdvancedCourse', (Course,), {}).**

Of course modules are also just objects, so they have an __init__ too, but their arguments are just self, name and docstring. So, you're passing one too many arguments.

You're actually just getting lucky here; if module and type happened to take the same number of arguments in their constructor, you'd end up with something very weird that acted sort of like a class in some ways, but not others, causing all kinds of subtle bugs.


If you want to play with this in the interactive interpreter, try this:

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

In Python 2.x, you don't want the metaclass=meta in the class header; you can just put object there. In 3.x, you don't want the __metaclass__=meta in the body; you can just put pass there.


* module is one of those "hidden" types not accessible by name in builtins, but you can get at it as types.ModuleType, or just by importing something and using type(Course).

** Actually, even an empty class has a few members in its dictionary. For example, in Python 3.3, there's always at least a __module__ attribute and a __qualname__ attribute.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.