Home > Net >  getting circular import while trying hinting python
getting circular import while trying hinting python

Time:11-26

I have 2 class (that are defined in two different package).

An A object as a "set" of B objects that all refer to the said A object.

Here is how it looks like :

the a.py :

from b import B
class A():
   def __init__(self, data):
      self.data = data
      self.Bs = {}

   def add_B(self, id, data_B):
      self.Bs[id] = B(data_B, self)

the b.py :

class B():
   def __init__(self, data, a_instance):
      self.data = data
      self.a = a_instance

so everything works preety good, but I'd like to hint python that the a_instance is indeed a class A object to have autocompletion in visual studio code.

At first i've tried to add from a import A and modify def __init__(self, data, a_instance : A): in the b.py file, but i've obviously got a circular import error

So I've been trying to use the typing package, and so added those lines to the a.py file :

from typing import NewType
A_type = NewType('A_type', A)

But I'm steel getting a circular import error.

Can Anyone explain me what I'm doing wrong ?

thanks for the help

PS: My classes actually have some complex methods and are defined in _a.py (resp. _b.py) and the __init__.py just import the class A and declare the A_type (resp. just import the class B)

CodePudding user response:

Use

  • typing.TYPE_CHECKING, a variable that's never true at runtime
  • the string form of a type annotation to refer to a name that is not in scope at runtime:
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from a import A

class B:
    def __init__(self, data, a_instance: "A"):
        ...

However, if you can restructure your code in a way that avoids circular imports altogether, all the better.

CodePudding user response:

You could try an abstract class with attributes of A and B, then implement each accordingly.

from collections.abc import abstractmethod, ABCMeta

class ABInerface(metaclass=ABCMeta):
    @property
    @abstractmethod
    def data(self):
        pass


    @data.setter
    @abstractmethod
    def data(self, value):
        pass


    @property
    @abstractmethod
    def Bs(self):
        pass


    @Bs.setter
    @abstractmethod
    def Bs(self, value):
        pass


    @property
    @abstractmethod
    def a(self):
        pass


    @a.setter
    @abstractmethod
    def a(self, value):
        pass


    @abstractmethod
    def add_B(self, id, data_B):
        pass

Then, create each class by extending the Interface meta class.

class B(ABInerface):
    def __init__(self, data, a_instance):
        self.data = data
        self.a = a_instance


class A(ABInerface):
    def __init__(self, data):
        self.data = data
    
    def add_B(self, id, data_B):
        self.Bs[_id] = B(data_B, self)
  • Related