On Dec 3, 2019, at 02:00, Serhiy Storchaka <storch...@gmail.com> 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 -- 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/II7MNXEJKUBL3XLCT7ZD77BYPW75CQ3L/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to