How to define circularly dependent data classes in Python 3.7+? How to define circularly dependent data classes in Python 3.7+? python python

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.)