pfnuesel
pfnuesel

Reputation: 15320

Inheritance in different modules

I have a parent and a child class, each in their own separate file. If these two classes are in one file, my MWE works. If I split them each into their separate files, I do not know how to import each other. Here is the MWE:

cat test.py
#!/usr/bin/env python3

from main_win import MainWin

test = MainWin()
test.click()

cat main_win.py
#!/usr/bin/env python3

from sub_win import SubWin

class MainWin:
    def __init__(self):
        print('Created main window')
    def click(self):
        options = SubWin()

cat sub_win.py
#!/usr/bin/env python3

from main_win import MainWin

class SubWin(MainWin):
    def __init__(self):
        print('Created sub window')

If I execute test.py and with the circular import defined as above, I get the following error:

ImportError: cannot import name 'MainWin' from 'main_win' (/home/basil/scratch/trash/pythonInheritance/p03/main_win.py)

Edit: There are valid comments questioning my class structure: Do I need inheritance? Could I add a super class, from which both classes above could inherit? These are very good comments and I will consider them carefully. Of course, the MWE will not be useful for you to weigh in in answering these questions. For now, let's just assume that the class structure is not to be changed. How can this problem then be solved? By merging the two modules into one, or is there another way?

Upvotes: 2

Views: 374

Answers (2)

Blckknght
Blckknght

Reputation: 104712

Your issue is that you have a circular import situation. The main_win module imports sub_win, and sub_win tries to import main_win back, but it doesn't work correctly because the MainWin class doesn't exist yet when the sub_win module tries to import it.

There are a few possible solutions.

Often the best solution is to get rid of the circular dependency between your two classes. Circular imports aren't forbidden, but a need for them often indicates sloppy design. There are many ways to fix the dependency too. In the example code, you don't need SubWin to inherit from MainWin at all, so you could just drop the inheritance. If they do need to share some common code or information, maybe they should both inherit it from a common ancestor (e.g. Window), where that shared stuff can go. Another option would make the two classes unrelated, but have MainWin pass the info SubWin needs to its constructor (e.g. options = SubWin(some_data)).

Another option might be to defer the import of sub_win to after MainWin exists in the main_win namespace. You can do this by moving the from sub_win import SubWin statement somewhere further down in the code. It could either remain at the module's top level somewhere below the definition of MainWin, or it could be put right inside of the click method, where it is used (so it would be a local variable in the function, rather than a global).

A final idea is to put your classes in the same module so you don't need the import statements at all. If your two classes are as tightly coupled as your current design suggests, then there's definitely no reason to separate them out into separate modules. Python is very different from some other programming languages (like Java) where the default is for every class to have its own source file. Python projects often feature large modules with many classes and global functions in them. You only need to split your modules up if they get so large that you regularly find yourself using part of their code without needing other parts.

Upvotes: 1

kungphu
kungphu

Reputation: 4849

You have a circular import. main_win.py imports sub_win.py which imports main_win.py...

To fix this and leave the code as-is, you could technically move from sub_win import SubWin into MainWin.click(). That's definitely not something I'd suggest, though, and you probably ought to go back to design and reconsider this approach to whatever it is you're attempting to achieve.

Upvotes: 1

Related Questions