On Dec 3, 2019, at 02:00, Serhiy Storchaka <[email protected]> wrote:
>
>
> I argued for | and |= as lesser evil. But there may be a problem. Dict and
> dict keys view are interchangeable in the context of some set operations:
> "in" checks for existence of the key and iterating yields keys. Currently
> both `dictkeys | dict` and `dict | dictkeys` return the same, the set
> containing the union of keys.
This is all just because a dict is an iterable of, and container of, its keys.
It’s not a set of them the way its keys view is, but it doesn’t have to be. And
you don’t need to do anything special to preserve that, just make sure
dict.__or__ and __ror__ don’t try to handle sets (or arbitrary iterables), only
mappings (or only dicts), and the set or view implementation will still work.
> >>> {1: 2}.keys() | {3}
> {1, 3}
> >>> {3} | {1: 2}.keys()
> {1, 3}
>
> What it will return if implement | for dicts? It should be mentioned in the
> PEP. It should be tested with a preliminary implementation what behavior is
> possible and more natural.
What is there to document or test here? There’s no dicts involved in either
operator, only a set and a key view, both of which are set types and implement
set union.
I think the question you wanted to ask is | between a dict and a set or view,
not between two sets or views. But as I said above, there’s an obvious right
thing to do there, and the obvious implementation does that. Of course it’s
still worth writing the tests, as well as the other usual __rspam__ tests that
go with every operator on the builtins.
>> ## Other objections
>
> The principal question about the result type was not mentioned above. `dict |
> dict` should return an exact dict for dict subclasses for the same reasons as
> not including __or__ in the Mapping API. We cannot guarantee the signature
> and the behavior of the constructor and therefore we have no way to create a
> copy as an instance of general dict subclass. This is why `dict.copy()`
> returns an exact dict. This is why `list + list`, `tuple + tuple`, `str +
> str`, `set | set`, `frozenset | frozenset`, etc, etc return an instance of
> the base class. This is why all binary operators for numbers (like `int +
> int`, `float * float`) return an instance of the base class.
Also because if you want MyInt + int and int + MyInt to return a MyInt, you can
do that trivially (as a subclass your __ror__ always gets precedence over the
base __or__), and if you want MyDicf.copy() to return a MyDict it’s even easier
(just override copy), so there’s no reason for the base class to even try to do
that for you.
So I agree, dict.__or__ should return a dict; anyone who wants MyDict to return
a MyDict can just override, as with every other operator on the builtins.
More generally, I think the design should follow all the other operators on
builtins on all such questions. For example, should dict.__or__ and __ior__
handle all the same values as update, or some more restricted set of types? The
same as set.__or__ and __ior__ vs. union, and list.__add__ and __iadd__ vs
extend, and so on. If they’re all consistent, and there’s no compelling reason
to add an inconsistency here, don’t.
_______________________________________________
Python-ideas mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/II7MNXEJKUBL3XLCT7ZD77BYPW75CQ3L/
Code of Conduct: http://python.org/psf/codeofconduct/