python / python/cpython

dataclasses astuple and asdict crash on recursive dataclass structures / dont support deepcopy memo

Đang mở
#94,345 5 bình luận 11 reaction 1 người được giao Xem trên GitHub

@ericvsmith đang làm issue này rồi.

Từ ngày 27/6/2022.

stdlib topic-dataclasses type-bug
Ngôn ngữ chính
Python
Star
77.2k
Fork
36k
Chỉ số merge pull request
Chỉ số pull request đang chờ

Mô tả

I don't see this mentioned anywhere and it seems a bit unusual, we can't use asdict() or astuple() with dataclasses that have cycles to each other. This is something that is handled by most other stdlib features such as deepcopy, dataclasses stringify, etc.

Example below

from __future__ import annotations

import dataclasses

# dataclasses support recursive structures

@dataclasses.dataclass
class A:
    b: list[B] = dataclasses.field(default_factory=list)

@dataclasses.dataclass
class B:
    a: A

# we can make a recursive structure
a1 = A()
b1 = B(a1)
a1.b.append(b1)

# stringify supports recursion
print(a1)
print(b1)


# asdict and astuple don't however, with no way to even work around
# it (like pass in a set to track already seen objects)

# recursion overflow
dataclasses.asdict(a1)

# same
dataclasses.astuple(a1)

output:

A(b=[B(a=...)])
B(a=A(b=[...]))
Traceback (most recent call last):
  File "/home/classic/dev/sqlalchemy/test4.py", line 29, in <module>
    dataclasses.asdict(a1)
  File "/opt/python-3.10.0/lib/python3.10/dataclasses.py", line 1232, in asdict
    return _asdict_inner(obj, dict_factory)
  File "/opt/python-3.10.0/lib/python3.10/dataclasses.py", line 1239, in _asdict_inner
    value = _asdict_inner(getattr(obj, f.name), dict_factory)
  File "/opt/python-3.10.0/lib/python3.10/dataclasses.py", line 1267, in _asdict_inner
    return type(obj)(_asdict_inner(v, dict_factory) for v in obj)
  File "/opt/python-3.10.0/lib/python3.10/dataclasses.py", line 1267, in <genexpr>
    return type(obj)(_asdict_inner(v, dict_factory) for v in obj)
  File "/opt/python-3.10.0/lib/python3.10/dataclasses.py", line 1239, in _asdict_inner
    value = _asdict_inner(getattr(obj, f.name), dict_factory)
  File "/opt/python-3.10.0/lib/python3.10/dataclasses.py", line 1239, in _asdict_inner

...

  File "/opt/python-3.10.0/lib/python3.10/dataclasses.py", line 1236, in _asdict_inner
    if _is_dataclass_instance(obj):
  File "/opt/python-3.10.0/lib/python3.10/dataclasses.py", line 1201, in _is_dataclass_instance
    return hasattr(type(obj), _FIELDS)
RecursionError: maximum recursion depth exceeded while calling a Python object

there seems to be no workaround as these two methods are pretty simple and don't accept any arguments like "check_recursion", IIUC there is also no directive on field() that would change this either?

Linked PRs
  • gh-151904

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.