Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handle circular dependencies in Python modules?

this is a case again where I'm running around in circles and I'm about to go wild.

I wish Python would analyze all files at first, so that it would know all identifiers from the beginning (I think like Java does).

I have a "main.py" and a "gui.py". Every file contains a class, that makes use of the class in the other file. When I try to run "main.py", the interpreter imports "gui", then in "gui.py" it imports "main", then it processes the whole main module and says: "Tee-hee, there is no class with the given name in gui.py."

How can I handle circular dependencies in Python with minimum fuss?

like image 383
rynd Avatar asked Apr 11 '12 20:04

rynd


People also ask

How do you resolve circular dependencies?

To resolve circular dependencies: Then there are three strategies you can use: Look for small pieces of code that can be moved from one project to the other. Look for code that both libraries depend on and move that code into a new shared library. Combine projectA and projectB into one library.

How do I fix the circular import error in Python?

If the error occurs due to a circular dependency, it can be resolved by moving the imported classes to a third file and importing them from this file. If the error occurs due to a misspelled name, the name of the class in the Python file should be verified and corrected.

What is module circular dependency?

In software engineering, a circular dependency is a relation between two or more modules which either directly or indirectly depend on each other to function properly. Such modules are also known as mutually recursive.


3 Answers

I thought I'd expand this into an answer instead of a comment.

It's worth noting that circular imports are generally a sign of bad design: instead of demanding the language suit your design, why not change that design?

There are ways around this problem in python:

  • The good option: Refactor your code not to use circular imports.
  • The bad option: Move one of your import statements to a different scope.

But no, you can't pre-parse files. That's not the way Python works, and if you look into how Python works, it's pretty obvious why.

like image 127
Gareth Latty Avatar answered Sep 27 '22 19:09

Gareth Latty


If you can't avoid circular imports, move one of the imports out of module-level scope, and into the method/function where it was used.

filea.py

import fileb

def filea_thing():
    return "Hello"

def other_thing():
    return fileb_thing()[:10]

fileb.py

def fileb_thing():
    import filea
    return filea.filea_thing() + " everyone."

That way, filea will only get imported when you call fileb_thing(), and then it reimports fileb, but since fileb_thing doesn't get called at that point, you don't keep looping around.

As others have pointed out, this is a code smell, but sometimes you need to get something done even if it's ugly.

like image 31
jcdyer Avatar answered Sep 27 '22 18:09

jcdyer


In general, dependencies should be a tree. Circular dependencies are not resolvable.

The usual way to solve this, though, is to do a "local import" of the required module at a level other than the global namespace.

like image 34
bukzor Avatar answered Sep 27 '22 18:09

bukzor