Reputation: 55
I have two classes Img
and ImgAnalyzer
each in their own module. ImgAnalyzer
accepts an Img
object as a parameter and performs various analyses on it, but I want to have the Img
object to 'own' the ImgAnalyzer
object, ie if I want to use the analyzer, I need to use it through the image.
ex:
img.py
from img_analyzer import ImgAnalyzer
class Img:
def __init__(self, *args, **kwargs):
# do thing
self.analyzer = ImgAnalyzer(self)
# other funcs
img_analyzer.py
from img import Img
class ImgAnalyzer:
def __init__(self, img: Image):
# do thing
# other funcs
Then I could access the analyzer from the image:
img = Img(params)
img.analyzer.func()
This inevitably causes a circular import error. The classes should be in separate files because they have different functions and are too long to reasonably combine anyway. I looked around here and on other sites but couldn't figure out how to fix it. How can I have a class operated through and dependent on another class without causing errors?
Upvotes: 1
Views: 153
Reputation: 458
Assuming that you only need to import Img
in img_analyzer.py
for the type checking
You can use the typing module's TYPE_CHECKING constant
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from img import Img
class ImgAnalyzer:
def __init__(self, img: 'Image'):
# do thing
# other funcs
Per the typing
documentation, typing.TYPECHECKING
is a special constant that is assumed to be True
by 3rd party static type checkers. It is False
at runtime
Upvotes: 0
Reputation: 4510
In short, don't.
Circular imports are already a bad enough attempt at sharing code between two files/modules. It seems like you want something more like an include directive found in other languages but even then circular include causes errors. Your case is compounded by the fact that you have circularly dependent instances. Circular class instantiation is legal in Python, but it's messy and can't be split into separate files.
In your case it seem like you're using ImgAnalyzer
as an extended methods package for Img
; you even call it as such img.analyzer.func()
. You can accomplish the same functionality by decoupling the classes from each other and making the import one-way. The identity of each instance of ImgAnalyzer
was completely dependent on an instance of Img
, so once we decouple that, we don't even NEED a class:
# img_analyzer.py
def func(img):
# do stuff on img, intended to be Img instance
import img_analyzer
class Img:
def __init__(self, *args, **kwargs):
# do thing
# other funcs
pic1 = Img(params)
img_analyzer.func(pic1)
Syntactically it does not look like Img
owns img_analyzer
or func
, but it didn't in your original code either. func
used to belong to the ImgAnalyzer
class and could be used like ImgAnalyzer.func(ImgAnalyzer(img), img)
, for which img.analyzer.func()
was just syntactic sugar. img_analyzer.func(pic1)
is just as neat and concise while avoiding circular dependency. func
still belongs to Img
in the sense that it was designed specifically for Img
instances.
Upvotes: 1