This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: dataclasses.astuple (and .asdict) do deepcopy on all fields
Type: behavior Stage: resolved
Components: Documentation Versions: Python 3.11, Python 3.10, Python 3.9
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: eric.smith Nosy List: andrei.avk, eric.smith, mandolaerik, miss-islington, serhiy.storchaka
Priority: normal Keywords: patch

Created on 2021-04-21 12:19 by mandolaerik, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 26154 merged andrei.avk, 2021-05-15 22:19
PR 29851 merged miss-islington, 2021-11-29 18:10
PR 29852 merged miss-islington, 2021-11-29 18:10
Messages (14)
msg391516 - (view) Author: Erik Carstensen (mandolaerik) Date: 2021-04-21 12:19
It seems that the 'dataclass.astuple' function does a deepcopy of all fields. This is not documented. Two problems:

1. Dictionary keys that rely on object identity are ruined:
    import dataclasses
    @dataclasses.dataclass
    class Foo:
        key: object
    key = object()
    lut = {key: 5}
    (y,) = dataclasses.astuple(Foo(x))
    # KeyError
    lut[y]

2. dataclasses can only be converted to a tuple if all fields are serializable:

    import dataclasses
    @dataclasses.dataclass
    class Foo:
        f: object
    foo = Foo(open('test.py'))
    dataclasses.astuple(foo)

->

TypeError: cannot pickle '_io.TextIOWrapper' object


In my use case, I just want a list of all fields. I can do the following as a workaround:
  (getattr(foo, field.name) for field in dataclasses.fields(foo))

Tested on Python 3.8.7 and 3.7.9.
msg391518 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2021-04-21 12:25
Unfortunately this can't be changed, although I suppose it should be documented.

In general I think this API was a mistake, and should not have been added. There are just too many cases where it doesn't do what you want, or where it fails.

I'd like to deprecate it and remove it (along with asdict), but I fear that would be too disruptive.

Your approach seems reasonable to me for your use case.
msg391519 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2021-04-21 12:52
Why deepcopy is used at all? It is a very specific feature which should not be used by default. If you want to make a deep copy of fields, you can call copy.deepcopy() explicitly.

    copy.deepcopy(dataclasses.astuple(obj))

or

    dataclasses.astuple(copy.deepcopy(obj))
msg391520 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2021-04-21 13:20
The reason for the deep copying was to support changing a hierarchy of dataclasses into something that could be JSON serialized. But it didn't really work out. It recurses into dataclasses, namedtuples, lists, tuples, and dicts, and deep copies everything else.

As I said, it's a design flaw.
msg394015 - (view) Author: Erik Carstensen (mandolaerik) Date: 2021-05-20 11:43
Would it make sense to make dataclasses iterable, like so?

    def __iter__(self):
        return (getattr(self, field.name) for field in fields(self))

With that in place, deprecating astuple would maybe be less disruptive?
msg394019 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2021-05-20 12:10
No, iteration is explicitly a non-goal of PEP 557. See the section on namedtuple for why: https://www.python.org/dev/peps/pep-0557/#why-not-just-use-namedtuple
msg396284 - (view) Author: Andrei Kulakov (andrei.avk) * (Python triager) Date: 2021-06-21 19:42
I've added a PR here: https://github.com/python/cpython/pull/26154
msg407241 - (view) Author: Andrei Kulakov (andrei.avk) * (Python triager) Date: 2021-11-29 01:48
Eric: I've closed a similar issue about asdict() and now updating the title to keep track of both in this issue. Let me know if you want to keep them separate instead.
msg407243 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2021-11-29 02:35
I think it's find to address both of these here.
msg407306 - (view) Author: miss-islington (miss-islington) Date: 2021-11-29 18:10
New changeset c1f93f0d378958dfae4f24aad0c0088e3e04e403 by andrei kulakov in branch 'main':
bpo-43905: Expand dataclasses.astuple() and asdict() docs (GH-26154)
https://github.com/python/cpython/commit/c1f93f0d378958dfae4f24aad0c0088e3e04e403
msg407310 - (view) Author: miss-islington (miss-islington) Date: 2021-11-29 18:30
New changeset 376b24e4f69cba53bae9856e9d076af47bb2b6c6 by Miss Islington (bot) in branch '3.9':
bpo-43905: Expand dataclasses.astuple() and asdict() docs (GH-26154)
https://github.com/python/cpython/commit/376b24e4f69cba53bae9856e9d076af47bb2b6c6
msg407311 - (view) Author: miss-islington (miss-islington) Date: 2021-11-29 18:33
New changeset 32f1491a9770b7f2989507ecf8f13ef35dd95b0b by Miss Islington (bot) in branch '3.10':
bpo-43905: Expand dataclasses.astuple() and asdict() docs (GH-26154)
https://github.com/python/cpython/commit/32f1491a9770b7f2989507ecf8f13ef35dd95b0b
msg407314 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2021-11-29 18:34
Thanks, @andrei.avk!
msg407316 - (view) Author: Andrei Kulakov (andrei.avk) * (Python triager) Date: 2021-11-29 18:44
Thank  you for reviewing Eric!
History
Date User Action Args
2022-04-11 14:59:44adminsetgithub: 88071
2021-11-29 18:44:26andrei.avksetmessages: + msg407316
2021-11-29 18:34:32eric.smithsetstatus: open -> closed
type: behavior
messages: + msg407314

resolution: fixed
stage: patch review -> resolved
2021-11-29 18:33:04miss-islingtonsetmessages: + msg407311
2021-11-29 18:30:46miss-islingtonsetmessages: + msg407310
2021-11-29 18:10:44miss-islingtonsetpull_requests: + pull_request28081
2021-11-29 18:10:41miss-islingtonsetpull_requests: + pull_request28080
2021-11-29 18:10:40miss-islingtonsetnosy: + miss-islington
messages: + msg407306
2021-11-29 02:35:27eric.smithsetmessages: + msg407243
components: + Documentation, - Library (Lib)
versions: + Python 3.9, Python 3.10, Python 3.11, - Python 3.7, Python 3.8
2021-11-29 01:48:56andrei.avksetmessages: + msg407241
title: dataclasses.astuple does deepcopy on all fields -> dataclasses.astuple (and .asdict) do deepcopy on all fields
2021-11-28 19:17:43andrei.avklinkissue44695 superseder
2021-06-21 19:42:03andrei.avksetmessages: + msg396284
2021-05-20 12:10:46eric.smithsetmessages: + msg394019
2021-05-20 11:43:00mandolaeriksetmessages: + msg394015
2021-05-15 22:19:51andrei.avksetkeywords: + patch
nosy: + andrei.avk

pull_requests: + pull_request24788
stage: patch review
2021-04-21 13:20:47eric.smithsetmessages: + msg391520
2021-04-21 12:52:41serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg391519
2021-04-21 12:25:03eric.smithsetassignee: eric.smith

messages: + msg391518
nosy: + eric.smith
2021-04-21 12:19:17mandolaerikcreate