many ways to import a module Link to heading

import X Link to heading

imports module X, and creates a reference to module in current namespace.

from X import a, b, c Link to heading

imports module X and creates references in the current namespace to given objects, in this case a, b, c.

what does python do to import module Link to heading

if module has already registered (sys.modules), it just passes.

else,

  • create new module object in dict
  • load module object
  • execute the module code in the new module’s namespace

what is a circular dependency Link to heading

two or more modules depend on each other. For example:

functionA():
	functionB()
	
functionB():
	functionA()
	---------------
	|				 |
	v				 |
functionA		  functionB
	|				 ^	
	|				 |
	---------------

Cons Link to heading

  • tight coupling between modules, so that reduced code reusability

  • source of potential failures, such as infinite recursions, memory leaks and cascade effects.

  • very difficult to debug and very hard to realize it is something related to circular imports.

what is a circular import Link to heading

see below three python files

#__init__.py

import module1

module1.function1()
#module1.py

import module2

def function1():
	module2.function2()
	
def function3():
	print('Goodbye, World!')
#module2.py

import module1

def function2():
	print('Hello, World!')
	module1.function3()

executing:

$ python __init__.py
Hello, World!  
Traceback (most recent call last):  
  File "__init__.py", line 3, in <module>
    module1.function1()
  File "/Users/scott/projects/sandbox/python/circular-dep-test/module1/__init__.py", line 5, in function1
    module2.function2()
  File "/Users/scott/projects/sandbox/python/circular-dep-test/module2/__init__.py", line 6, in function2
    module1.function3()
AttributeError: 'module' object has no attribute 'function3'  

When Python imports a module, it checks the module registry to see if the module was already imported. If the module was already registered, Python uses that existing object from cache. The module registry is a table of modules that have been initialized and indexed by module name. This table can be accessed through sys.modules.

If it was not registered, Python finds the module, initializes it if necessary, and executes it in the new module’s namespace.

Modules are executed during import, and new functions and classes won’t appear in the module’s namespace until the def (or class) statement has been executed.

in this case, let’s analyze it.

__init__.py import module 1, so sys.modules contains module 1(empty). module 1 imports module2, so sys.modules contains module 2 (empty). next def will be executed, it calls module1.function3(). But notes that module 1 is empty right now in dict.

How to fix circular dependencies/imports Link to heading

Simple solution, not for flask or anyother framework:

  • merge modules together to a larger module.

However, merged module may have unrelated functions, this is called tight coupling.

  • Another solution is to import only needed. The above file can be rewritten as
# module 1

def function1():  
    import module2
    module2.function2()

def function3():  
    print('Goodbye, World!')
  • in flask, people tend to import at last to avoid circular imports