Suppose that class A
has a member whose type is class B
, and class B
has a member whose type is class A
.
In Scala or Kotlin, you can define the classes in any order without worries in this case because the firstly-defined class can use the secondly-defined class as usual, even in case/data classes.
However in Python, the following code
class A:
b = B()
class B:
a = A()
throws a compile error because class B
is not defined when class A
is being defined.
You can work around this simple case, like in this answer
class A:
pass
class B:
a = A()
A.b = B()
However, this way does not work for data classes in Python because assigning members after the definition of data classes will not update the auto-generated methods of the data classes, which makes the usage of "data class" useless.
@dataclass
class A:
b: B # or `b: Optional[B]`
@dataclass
class B:
a: A # or `a: Optional[A]`
How can I avoid this problem?
There are several ways to solve circular dependencies like this, see Type hints: solve circular dependency
You can always apply the decorator manually (and update the annotations), like @Nearoo's answer shows.
However, it might be easier to "forward declare" the class:
class A:
pass
@dataclass
class B:
a: A
@dataclass
class A:
b: B
Or simply use a forward reference:
@dataclass
class B:
a: 'A'
@dataclass
class A:
b: B
The cleanest is to import Python 4.0's behavior (if you can):
from __future__ import annotations
@dataclass
class B:
a: A
@dataclass
class A:
b: B