On 12/31/2020 3:59 PM, Eric V. Smith wrote:
On 12/31/2020 3:18 PM, Christopher Barker wrote:
On Thu, Dec 31, 2020 at 11:51 AM Eric V. Smith <eric@trueblade.com> wrote:
I'd suggest you just write your own function to do this. I consider
adding dataclasses.asdict and .astuple to be mistakes.

I agree there -- if you want something that can be used like this -- use a dict in the first place :-)

Eric: what do you think about adding a "shallow" (or "deep") flag to dataclasses.asdict()
 that would then upack only the top-level dataclass?

I'm not opposed to it. Since I can't make asdict/astuple go away, I might as well make them more useful.

Currently a deep copy is made:

class F:
    l: Optional[list]
    f: Optional["F"]

mylist = [1, 2, 3]
f = F(mylist, None)
f1 = F(mylist, f)

>>> f = F(mylist, None)
>>> f1 = F(mylist, f)

>>> asdict(f)
{'l': [1, 2, 3], 'f': None}
>>> asdict(f)['l'] is mylist

>>> asdict(f1)
{'l': [1, 2, 3], 'f': {'l': [1, 2, 3], 'f': None}}
>>> asdict(f1)['f']['l']
[1, 2, 3]
>>> asdict(f1)['f']['l'] is mylist

I think what we'd want is to just turn the top-level dataclass in to a dict, but then not recurse _and_ only make a shallow copy.

Something like:

>>> asdict(f1, mumble_mumble=False)
{'l': [1, 2, 3], 'f': F(l=[1, 2, 3], f=None)}
>>> asdict(f1)['l'] is mylist
>>> asdict(f1)['f'] is f

Since the 'f' member wouldn't be a copy (I hope there's agreement here), I'd think the 'l' member should also not be a copy.

The question then is: what's a good name for my "mumble_mumble" argument? Does "deep=False" make sense? Or is it "recurse=False"?  Or maybe it should just be a separate function. The intent of doing the shallow copy seems different than asdict() currently: asdict() is designed to turn everything to a dict, recursively. The target is json, but I'm not sure how well it fills that need. As I said, I don't think asdict() is a great example of API design, and I wish I'd left it out.

Having some convoluted combination of not recursing but making a deep copy seems wrong to me.