madtyn
madtyn

Reputation: 1549

ImportError: cannot import name between two files importing the same

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

Answers (1)

bruno desthuilliers
bruno desthuilliers

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

Related Questions