Python import circular dependency

Let's say I have the following directory structure:

a\ __init__.py b\ __init__.py c\ __init__.py c_file.py d\ __init__.py d_file.py 

In package a __init__.py package c imported. But c_file.py imports abd .

The program does not work, saying b does not exist when c_file.py tries to import abd . (And it really does not exist, because we were in the middle of importing it.)

How can this problem be fixed?

+60
python dependencies python-import circular-dependency
Oct 12 '09 at 19:19
source share
5 answers

If a depends on c and c depends on a, they are not actually the same unit, then?

You should really study why you split a and c into two packages, because either you have code that you have to split into another package (so that they depend on this new package, but not from each other), or you need to combine them in one package.

+53
Oct 12 '09 at 19:33
source share

You can defer import, for example, in a/__init__.py :

 def my_function(): from abc import Blah return Blah() 

that is, defer import until it is really needed. However, I would also carefully consider the definitions / use of packages, since a cyclic dependency such as the one indicated may indicate a design problem.

+139
Oct 12 '09 at 19:27
source share

I asked this question a couple of times (usually when dealing with models that should know about each other). A simple solution is to simply import the whole module and then reference what you need.

So, instead of doing

 from models import Student 

in one and

 from models import Classroom 

in another, just

 import models 

in one of them, then call the models. Classes when you need it.

+19
Oct 04 '13 at 16:18
source share

The problem is that when you start from the default directory, only packages that are subdirectories are displayed as candidate import, so you cannot import the abd file. However, you can import bd since b is an additional package.

If you really want to import abd into c/__init__.py , you can do this by changing the system path one directory above a and changing the import to a/__init__.py to import abc

Your a/__init__.py should look like this:

 import sys import os # set sytem path to be directory above so that a can be a # package namespace DIRECTORY_SCRIPT = os.path.dirname(os.path.realpath(__file__)) sys.path.insert(0,DIRECTORY_SCRIPT+"/..") import abc 

An additional difficulty arises when you want to run modules in c as scripts. Here packages a and b do not exist. You can hack __int__.py in the c directory to point sys.path to the top level directory and then import __init__ into any modules inside c to be able to use the full path to import abd I doubt it is good practice to import __init__.py , but this worked for my use cases.

0
Aug 30 '15 at 23:33
source share

Another solution is to use proxies for d_file.

For example, say you want to separate the blah class with c_file. So d_file contains:

 class blah: def __init__(self): print("blah") 

Here is what you type in c_file.py:

 # do not import the d_file ! # instead, use a place holder for the proxy of d_file # it will be set by a __init__.py after imports are done d_file = None def c_blah(): # a function that calls d_file blah d_file.blah() 

And in init .py:

 from bc import c_file from bd import d_file class Proxy(object): # module proxy pass d_file_proxy = Proxy() # now you need to explicitly list the class(es) exposed by d_file d_file_proxy.blah = d_file.blah # finally, share the proxy with c_file c_file.d_file = d_file_proxy # c_file is now able to call d_file.blah c_file.c_blah() 
-3
Jul 17 '12 at 11:33
source share



All Articles