How to avoid circular imports in Python?
Only import the module, don't import from the module:
Consider a.py
:
import b
class A:
def bar(self):
return b.B()
and b.py
:
import a
class B:
def bar(self):
return a.A()
This works perfectly fine.
How to avoid circular import looping
You have a few options:
- put all your code in one file, if it needs to be this tightly linked
value = 5
def set():
value = 6
set()
put the code that uses parts from the others in a third file, or in other words break up your code so you avoid the circular references - your example is a bit too simple to make that work though.
pass values to functions you want to use, or pass objects you want to modify; importing and modifying another module's globals isn't a very good way to design your program anyway:
# this is my_module.py
def set_value(x):
x.value = 6
def increment(x):
return x + 1
And elsewhere:
import my_module
class X:
value = 5
x = X()
my_module.set_value(x)
y = 5
y = my_module.increment(y)
Avoiding circular imports with type annotations in situations where __future__.annotations is insufficient
In the most cases using typing.TYPE_CHECKING
helps to resolve circular import issues.
# a.py
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from b import B
class A: pass
def foo(b: B) -> None: pass
# b.py
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from a import A
class B: pass
def bar(a: A) -> None: pass
# __main__.py
from a import A
from b import B
However, for exactly your MRE it won't work. If the circular dependency is introduced not only by type annotations (e.g. your type aliases), the resolving may become really tricky.
If you don't need Foo
available at runtime in your example, it can be declared in if TYPE_CHECKING:
block too, mypy will interpret that properly. If it is for runtime too, then everything depends on exact code structure (in your MRE dropping import b
is enough). Union type can be declared in separate file that imports a
, b
and c
and creates Union. If you need this union in a
, b
or c
, then things are a bit more complicated, probably some functionality needs to be extracted into separate file d
that creates union and uses it (also the code will be a bit cleaner this way, because every file will contain only common functionality).
Avoiding circular (cyclic) imports in Python?
Merge any pair of modules that depend on each other into a single module. Then introduce extra modules to get the old names back.
E.g.,
# a.py
from b import B
class A: whatever
# b.py
from a import A
class B: whatever
becomes
# common.py
class A: whatever
class B: whatever
# a.py
from common import A
# b.py
from common import B
What happens when using mutual or circular (cyclic) imports in Python?
There was a really good discussion on this over at comp.lang.python last year. It answers your question pretty thoroughly.
Imports are pretty straightforward really. Just remember the following:
'import' and 'from xxx import yyy' are executable statements. They execute
when the running program reaches that line.If a module is not in sys.modules, then an import creates the new module
entry in sys.modules and then executes the code in the module. It does not
return control to the calling module until the execution has completed.If a module does exist in sys.modules then an import simply returns that
module whether or not it has completed executing. That is the reason why
cyclic imports may return modules which appear to be partly empty.Finally, the executing script runs in a module named __main__, importing
the script under its own name will create a new module unrelated to
__main__.Take that lot together and you shouldn't get any surprises when importing
modules.
How to avoid circular imports?
Dump the config.py file.
initialize your variables in vitals.py and change the variables from GUI.py.
i.e. inside vitals.py:
weight = 0
and inside GUI.py
import vitals
vitals.weight = weightVar.get()
Edit:
the new problem you now have is because your value of bmr depends on weight.
when you do
import vitals
bmr gets calculated with initialized value.
When you want to have bmr calculated dynamically you need to change it to a function. So in vitals.py:
def bmr(weight, height, age):
return Decimal(((10 * float(weight)) + (6.25 * height) - (5 * age) + 5))
And then you call it from GUI.py:
import vitals
vitals.weight = weightVar.get()
print(vitals.bmr(vitals.weight, vitals.height, vitals.age))
edit2:
you need to do this for all values that are dependent on other variables
Related Topics
Python Socket Not Receiving Without Sending
How to Delete Rows from a Pandas Dataframe Based on a Conditional Expression
Good Python Modules for Fuzzy String Comparison
Putting a Simple If-Then-Else Statement on One Line
Creating a Simple Xml File Using Python
How Are Post and Get Variables Handled in Python
I Need to Securely Store a Username and Password in Python, What Are My Options
What's the Fastest Way of Checking If a Point Is Inside a Polygon in Python
How to Do a Recursive Sub-Folder Search and Return Files in a List
Display a Decimal in Scientific Notation
Pandas Groupby: How to Get a Union of Strings
How to Print Pandas Dataframe Without Index