Cosmin Polifronie
Cosmin Polifronie

Reputation: 67

Python import statement doesn't work depending on position in __init__.py

Let's take a folder structure like this:

project_root
│   start.py
└───Application
    └───ViewModels
        │   __init__.py
        │   MagnifierWindowViewModel.py
        │   MainViewModel.py
        │   MainWindowViewModel.py
        │   PlotterWindowViewModel.py

These are the contents of the files:

start.py

from Application.ViewModels import MainViewModel

if __name__ == "__main__":
    mainViewModel = MainViewModel()

Application\ViewModels\__init__.py

from Application.ViewModels.PlotterWindowViewModel import *
from Application.ViewModels.MagnifierWindowViewModel import *
from Application.ViewModels.MainViewModel import *
from Application.ViewModels.MainWindowViewModel import *

Application\ViewModels\MagnifierWindowViewModel.py

class MagnifierWindowViewModel(object):
    def __init__(self):
        pass

Application\ViewModels\MainViewModel.py

from Application.ViewModels import MagnifierWindowViewModel, MainWindowViewModel, PlotterWindowViewModel

class MainViewModel(object):
    def __init__(self):
        self.mainWindowVM = MainWindowViewModel()
        self.magnifierWindowVM = MagnifierWindowViewModel()
        self.plotterWindowVM = PlotterWindowViewModel()

Application\ViewModels\MainWindowViewModel.py

class MainWindowViewModel(object):
    def __init__(self):
        pass

Application\ViewModels\PlotterWindowViewModel.py

class PlotterWindowViewModel(object):
    def __init__(self):
        pass

With this structure, I get this error:

Traceback (most recent call last):
  File "project_root/start.py", line 4, in <module>
    mainViewModel = MainViewModel()
  File "project_root/Application/ViewModels/MainViewModel.py", line 5, in __init__
    self.mainWindowVM = MainWindowViewModel()
TypeError: 'module' object is not callable

But if I put the last line in Application\ViewModels\__init__.py first, the application runs just fine. Why is that?

The reason I have this Application\ViewModels\__init__.py is so that I can write

from Application.ViewModels import MagnifierWindowViewModel

instead of

from Application.ViewModels.MagnifierWindowViewModel import MagnifierWindowViewModel

Upvotes: 2

Views: 291

Answers (1)

user2357112
user2357112

Reputation: 280973

You've stuck every class in its own module named the exact same thing as the class. That's a really bad idea for the reasons you're seeing here: it is way too easy to get the class and the module mixed up.

When your MainViewModel.py performs its imports:

from Application.ViewModels import MagnifierWindowViewModel, MainWindowViewModel, PlotterWindowViewModel

what gets imported depends on how much of Application\ViewModels\__init__.py has executed. If this line has not executed:

from Application.ViewModels.MainWindowViewModel import *

then the import in MainViewModel.py imports the MainWindowViewModel module. If the import * has executed, then it shadows the MainWindowViewModel module with the MainWindowViewModel class defined inside the module, so the import in MainViewModel.py imports the MainWindowViewModel class.

Upvotes: 1

Related Questions