Sasgorilla
Sasgorilla

Reputation: 3130

How can I resolve a circular import of two Python classes in the same module?

I have two tightly-coupled Python classes that need references to each other (at the class, not instance, level). How can I resolve the circular imports? Ideally I'd like to be able to make it work either within the same module or between two distinct modules, but I'll settle for one or the other.

# yin_yang.py

class MyYin(Yin):
    __yang__ = MyYang

class MyYang(Yang):
    __yin__ = MyYin

Upvotes: 4

Views: 849

Answers (3)

Ivan Velichko
Ivan Velichko

Reputation: 6719

While @phillip-martin's response is the most pythonic one, there is an alternative way to accomplish the task:

from werkzeug import LocalProxy


class MyYin:
    __yang__ = LocalProxy(lambda: MyYang)
    foo = 42


class MyYang:
    __yin__ = LocalProxy(lambda: MyYin)
    bar = 9002


print(MyYin.__yang__.bar)
print(MyYang.__yin__.foo)

And the magic behind LocalProxy trick comes from overriding all the __getattr__, __setattr__, __etc__ methods. Check it out in the werkzeug repo.

Upvotes: 2

lmiguelvargasf
lmiguelvargasf

Reputation: 70003

When the Python interpreter finds a class declaration, it creates a new scope and executes the code inside the class in this code block, i.e., all class variables are instantiated when the class declaration is executed.

You can avoid this in a really simple manner:

class MyYin(Yin):
    pass


class MyYang(Yang):
    __yin__ = MyYin

MyYin.__yang__ = MyYang

or

class MyYang(Yang):
    pass


class MyYin(Yin):
    __yang__ = MyYang


MyYang.__yin__ = MyYin

Upvotes: 0

Phillip Martin
Phillip Martin

Reputation: 1970

You could set the class attributes for one or both classes after they have been declared.

class MyYin(Yin):
    pass

class MyYang(Yang):
    __yin__ = MyYin

MyYin.__yang__ = MyYang

Upvotes: 5

Related Questions