Avoiding circular (cyclic) imports in Python?

One way is to use import x without using the "from" keyword. So, you always refer to things with their namespace.

Is there another way? how to do something like in c ++ ifnotdef __b__ def __b__ type of thing?

+7
source share
3 answers

Combine any pairs of modules that depend on each other in one module. Then enter additional modules to return the old names.

eg.

# 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 
+10
source

Circular imports are the "smell of code," and often (but not always) indicate that some refactoring will be appropriate. For example, if Ax uses By and By uses Az , then you might consider moving Az to your own module.

If you think you need circular imports, I would recommend importing the module and referencing objects with fully qualified names (i.e. import A and use Ax , not from A import x ).

+5
source

If you are trying to do from A import * , the answer is simple: do not do this. Usually you should do import A and refer to qualified names.

For fast and dirty scripts and interactive sessions, this is a perfectly reasonable thing, but in such cases you will not run cyclic import versions.

There are times when it makes sense to do import * in real code. For example, if you want to hide a module structure that is complex or dynamically generated or changes frequently between versions, or if you complete some other package that is too deeply nested, import * might make sense with a "wrapper module" or a top-level package module. But in this case, the import that you import will import you.

In fact, it’s hard for me to imagine a case where import * is justified, and circular dependencies are even possible.

If you are doing from A import foo , there are ways around this (e.g. import A , then foo = A.foo ). But you probably don't want to do this. Again, think about whether you really need to bring foo into your names, names whose names are characteristics, not a problem for the job.

If you execute from A import foo just for the convenience of implementing your functions, because A is actually long_package_name.really_long_module_name , and your code is unreadable due to all the calls to long_package_name.really_long_module_name.long_class_name.class_method_that_puts_me_over_80_characters , you can always remember long_package_name.really_long_module_name.long_class_name.class_method_that_puts_me_over_80_characters , long_package_name.really_long_module_name.long_class_name.class_method_that_puts_me_over_80_characters , import long_package_name.really_long_module_name as P , and then use P for qualified calls.

(Also remember that with any from done for ease of implementation, you probably want to specify __all__ to make sure that the imported names are not part of your namespace if someone does import * on you from an interactive session.)

In addition, as others have noted, most, but not all, cases of circular dependencies are a symptom of poor design, and refactoring your modules in a reasonable way will fix it. And on rare occasions when you really need to bring names to your namespace, and a circular set of modules is actually a better design, some artificial refactoring may be a better choice than foo = A.foo .

0
source

All Articles