1

In C# code can be organized into multiple projects. Say I have two projects ProjectA and ProjectB. I can setup ProjectB to reference ProjectA. Once I do that the classes in ProjectB can use the classes defined in ProjectA. But classes in ProjectA cannot use the classes defined in ProjectB, and ProjectA cannot also be made to reference ProjectB.

Is there any equivalent to this in python? I think a package in python is a close equivalent to a project in C#. Nothing seems to prevent circular dependencies between packages in python though. I can have modules in PackageB reference modules in PackageA, and at the same time modules in PackageA reference modules in PakcageB. This can quickly devolve into a messy web of dependencies between packages.

Are there constructs or tools in python to prevent circular dependencies the way that projects do in c#?

innominate227
  • 11,109
  • 1
  • 17
  • 20
  • If the language allows it then I wouldn't worry about it too much (unless it is a bug in the language). Please see [this](https://stackoverflow.com/questions/744373/circular-or-cyclic-imports-in-python), it may help. I could be totally wrong about not worrying about it, but then again why would a language allow such a thing. – CodingYoshi Oct 24 '18 at 02:30
  • What is your use-case in this case? Your problem sounds more like one of design. Can you define ABC (Abstract Base Classes)? – Tim Oct 24 '18 at 02:45
  • No specific use case for this question. I find that because c# disallows such circular dependencies between projects it helps reduce coupling. Was hoping to find similar mechanisms to reduce coupling in python. – innominate227 Oct 24 '18 at 14:29

2 Answers2

0

Python allows circular dependencies, but only very rarely is it useful.

Generally speaking though, two packages depending on each other aren't considered a circular dependency, only two modules. Ex

moduleB.py

from moduleA import B

class C:
    # definition
B.start()

moduleA.py

from moduleB import C

class B:
    @staticmethod
    def start():
# remaining definitions
d = C()

However, circular dependencies like the one mentioned here just won't work-- the default import machinery won't allow it and you'll get an error, or the imports would keep calling each other until you hit a stack overflow, unless you implement import hooks to solve it.

If packageA.moduleA imports something from packageB.moduleA, and packageB.moduleB imports from packageA.moduleA, that is allowed.

Community
  • 1
  • 1
13steinj
  • 427
  • 2
  • 9
  • 16
0

The answer is no: there’s no way for a package A to detect that another package B it depends on has imported A again. This is because an import executes no code if the target has already been imported elsewhere.

# A/__init__.py
from B import foo
def go(): return foo.real()

# B/foo.py
import A
def use(): return A.go()
def real(): return 42

This a direct circularity between modules, not just packages, and it still works: if A is imported first, B.foo.A becomes a reference to the incomplete A (without go), but that doesn’t matter until use is called. That incomplete reference is created without any notification to, or check by, A.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76