How to define circularly dependent data classes in Python 3.7+?
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@dataclassclass B: a: A@dataclassclass A: b: B
Or simply use a forward reference:
@dataclassclass B: a: 'A'@dataclassclass A: b: B
The cleanest is to import Python 4.0's behavior (if you can):
from __future__ import annotations@dataclassclass B: a: A@dataclassclass A: b: B
You can achieve your goal by applying the dataclass
decorator only after we injected the field b
into A
. For that, we simply have to add the type annotation into A
's __annotations__
-field
The following code solves your problem:
class A: b: None # Note: __annotations__ only exists if >=1 annotation exists@dataclassclass B: a: AA.__annotations__.update(b=B) # Note: not the same as A.b: BA = dataclass(A) # apply decorator
Concerning the safety and validity of this method, PEP 524 states that
..at the module or class level, if the item being annotated is a simple name, then it and the annotation will be stored in the __annotations__ attribute of that module or class. [This attribute] is writable, so this is permitted:
__annotations__['s'] = str
So adding a type annotation later on by editing __annotations__
is identical to defining it at the class definition.
As python is script language - there is no way to do it with @dataclass
. Because there is no "autowired" (dependency injection) mechanism in python.At this moment if you need circular dependency - you should use one of class as regular.
class A: b = None@dataclassclass B: a: Aa = A()a.b = B(a)
Python compiler goes through each line, without jumping from class/function definition. And when compiler/interpreter see following line b: B
and it didn't see B
class before - it will throw an exception NameError: name 'B' is not defined
I would like to believe that there is way to do that(circular dependency for @dataclass
), but the truth is cruel. (There are many things that you can do in Java/other language and can't do in python. Another direction of this statement is truthful either.)