On Mon, Dec 28, 2020 at 12:33 PM Guido van Rossum <gu...@python.org> wrote:
> On Mon, Dec 28, 2020 at 12:15 PM Christopher Barker <python...@gmail.com> > wrote: > >> Though frankly, I would rather have had it use .items() -- seems more >> efficient to me, and you do need both the keys and the values, and items() >> is just as much part of the Mapping API as keys. >> > > There may be a (small) performance issue with that -- items() requires > creating a tuple object for each key/value pair. > it does look like items() is a tad faster (dict with 1000 items), but not enough to matter: In [61]: %timeit {k: d[k] for k in d.keys()} 112 µs ± 1.02 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) In [62]: %timeit {k: v for k, v in d.items()} 92.6 µs ± 1.9 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) Anyway, of course it's too late to change. And there are probably other > "protocols" that check for the presence of keys and __getitem__(). Also, in > a sense keys() is more fundamental -- deriving keys() from items() would be > backwards (throwing away the values -- imagine a data type that stores the > values on disk). > Does there need to be a single defined "protocol" for a mapping (other than the ABC)? -- that is, would **unpacking be able to use .items() and keys() be used in other contexts? And why does ** unpacking need to check at all (LBYL) couldn't it simply do something like: {k: d[k] for k in d} sure, there could occasionally be a Sequence for which that would happen to work (like a range object for instance), but then it would be unlikely to result in the expected result anyway -- just like many other uses of Duck typing. Or not, and it could still be correct. But as you say -- too late the change now anyway. To the OP: you suggested that you had, I think, four ways to make a dataclass "unpackable", but none were satisfactory. How about this decorator: def make_mapping(cls): def __getitem__(self, key): if key in self.__dataclass_fields__: return self.__dict__[key] else: raise KeyError(key) def keys(self): return self.__dataclass_fields__.keys() cls.__getitem__ = __getitem__ cls.keys = keys return cls @make_mapping @dataclasses.dataclass class Point: x: int y: int p = Point(1, 2) print(p) print({**p}) print(dict(p)) -CHB Side Question: when should one use __dict__ vs vars() vs getattr() ??? all three work in this case, but I'm never quite sure which is prefered, and why. > > >> But there is an argument that the ** operator should be able to be >> supported only with dunder methods -- which could be done if it used the >> iterator protocol to get the keys, rather than the keys() method, which >> does not appear to work now. though to be fair, all you need to do to get >> that is add a __len__ and derive from Mapping. >> > > If we had to do it all over from scratch we would probably design mappings > and sequences to be differentiably using dunders only. But it's about 31 > years too late for that. And looking at the mess JavaScript made of this > (sequences are mappings with string keys "0", "1" and so on), I'm pretty > happy with how Python did this. > > -- > --Guido van Rossum (python.org/~guido) > *Pronouns: he/him **(why is my pronoun here?)* > <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/> > -- Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/ZPDXCZSYVPXMV54T54BUH233SYYFQ7FA/ Code of Conduct: http://python.org/psf/codeofconduct/