Create a gist now

Instantly share code, notes, and snippets.

Embed
Circular imports in Python 2 and Python 3: when are they fatal? When do they work?

When are Python circular imports fatal?

In your Python package, you have:

  • an __init__.py that designates this as a Python package
  • a module_a.py, containing a function action_a() that references an attribute (like a function or variable) in module_b.py, and
  • a module_b.py, containing a function action_b() that references an attribute (like a function or variable) in module_a.py.

This situation can introduce a circular import error: module_a attempts to import module_b, but can't, because module_b needs to import module_a, which is in the process of being interpreted.

But, sometimes Python is magic, and code that looks like it should cause this circular import error works just fine!

When does it work and when does it not? Why does it work when it does?

When it works

Top of module; no from; Python 2 only

Imports at top of module. import MODULE. Function references MODULE.ATTRIBUTE. Since import MODULE is an implicit relative import from the current directory, this might not work for importing from other packages. Since import MODULE is a syntax error in Python 3 this works in Python 2 only so is not future-proof.

# pkg/module_a.py                             # pkg/module_b.py
import module_b                               import module_a
def action_a():                               def action_b():
    print(module_b.action_b.__name__)             print(module_a.action_a.__name__)

Top of module; no from; no relative

Imports at top of module. import PACKAGE.MODULE. Function references PACKAGE.MODULE.ATTRIBUTE. Since import .MODULE is a syntax error, relative imports can't be used here; modules must know their containing package's name.

# pkg/module_a.py                             # pkg/module_b.py
import pkg.module_b                           import pkg.module_a
def action_a():                               def action_b():
    print(pkg.module_b.action_b.__name__)         print(pkg.module_a.action_a.__name__)

Bottom of module; import attribute, not module; from okay.

Imports at bottom of module (or at least after referenced attribute). from PACKAGE.MODULE import ATTRIBUTE. May be relative, like from .MODULE import ATTRIBUTE. Function references ATTRIBUTE.

# pkg/module_a.py                             # pkg/module_b.py
def action_a():                               def action_b():
    print(action_b.__name__)                      print(action_a.__name__)
from .module_b import action_b                from .module_a import action_a

Top of function; from okay

Imports at top of function. from PACKAGE import MODULE. PACKAGE may be relative, like .. Function references MODULE.ATTRIBUTE. This becomes ugly (but still works) if you have several functions that all refer to the same MODULE.

# pkg/module_a.py                             # pkg/module_b.py                
def action_a():                               def action_b():
    from . import module_b                        from . import module_a
    print(module_b.action_b.__name__)             print(module_a.action_a.__name__)
@RomanKhudobei

This comment has been minimized.

Show comment
Hide comment
@RomanKhudobei

RomanKhudobei Jun 7, 2018

Hi. Thanks for this information. I'm learning Django Rest Framework and faced with cyclic import. I was searching a lot but anything didn't work. From your suggestions only last works for me. I don't know why. Maybe I do something wrong. Looks ugly, but working. If you can look at my attempts, I'll be very thankful.

Hi. Thanks for this information. I'm learning Django Rest Framework and faced with cyclic import. I was searching a lot but anything didn't work. From your suggestions only last works for me. I don't know why. Maybe I do something wrong. Looks ugly, but working. If you can look at my attempts, I'll be very thankful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment