Reputation: 1549
I have this code
mainModule
from src.comp.mypackage.wait import Wait
from src.comp.mypackage.men import Men, MenItem
""" Code and stuff using Men and MenItem """
if __name__ == '__main__':
MenuTestDrive.main()
men
from abc import ABCMeta, abstractmethod
from src.comp.mypackage.util import NullUtil, CompUtil
util
from src.comp.mypackage.stack import Stack
from src.comp.mypackage.men import Men
""" Code and stuff using Men and MenItem """
and when running mainModule I'm being given this error:
Traceback (most recent call last):
File "/home/user/PycharmProjects/pythonProj/pythonDesignPatterns/src/comp/mypackage/mainModule.py", line 2, in <module>
from pythonDesignPatterns.src.comp.mypackage.men import Men, MenItem
File "/home/user/PycharmProjects/pythonProj/pythonDesignPatterns/src/comp/mypackage/men.py", line 2, in <module>
from pythonDesignPatterns.src.comp.mypackage.iterator import NullUtil, CompUtil
File "/home/user/PycharmProjects/pythonProj/pythonDesignPatterns/src/comp/mypackage/util.py", line 2, in <module>
from pythonDesignPatterns.src.comp.mypackage.men import Men
ImportError: cannot import name 'Men'
I'm using pyCharm, but the error at the command line is the same.
I could provide more code, but I don't think there is anything fancy with the use of classes and would only distract.
Where should I being to look for failures?
Upvotes: 1
Views: 1043
Reputation: 77912
TL;DR : python doesn't allow circular imports, so you can't have module men
importing from module util
if module util
imports from module men
.
Longer answer:
You have to understand that in Python import
, class
, def
etc are actually executable statements and everything (or almost) happens at runtime. When a module is imported for the first time in a given process, all the top-level statements are executed sequentially, a module
instance object is created with all top-level names as attributes (note that class
, def
and import
all bind names) and inserted into the sys.modules
cache dict so next import of the same module will retrieve it directly from the cache.
In your case, when first imported, the men
module tries to import the util
module, which is not in sys.modules
yet so the Python runtime locates the util.py (or .pyc) file and executes it. Then it reaches the from src.comp.mypackage.men import Men
. At this point, men.py
has not yet been fully executed and so has no Men
attribute.
The canonical solution is to either extract circular dependancies into a third module or merge the two modules into a single one, depending one what makes sense for your concrete case (the goal being, as always, to have modules with low coupling and high cohesion). FWIW, circular dependancies are considered bad design whatever the language and even if the language supports them.
Sometimes (most often in complex frameworks that impose some particular structure to your code and a specific import order), you can end up with circular dependancies chains that are either much more complex (like A.funcX depends on B.y, B depends on C which depends on D which depends on E which finally depends on A.funcZ) and/or very difficult to cleanly refactor in a way that makes sense. As a last resort you still have the possibility to defer some import statement within the function (in the above it would be inside A.funcX
). This is still considered a bad practice and should really only be used as the very last resort.
As a side note: from your packages naming scheme I can smell a strong Java influence. Python is not Java ! Not that there's anything wrong with Java, it's just that these are two wildly different languages, with wildly different designs, idioms and philosopies.
Trying to forcefit Java idioms and habits in Python will be an experience in pain and frustration at best (been here, done that...), so my advice here would be: forget about mostly anything you learned with Java and start learning Python instead (not just the syntax - syntax is actually only a part of a language and not necessarily the most important one). In Python we favor flat over nested, and don't try to have one module per class, you can have a whole (micro)framework in one single module, that's ok if there's no practical reason to split it into submodules.
Upvotes: 2