Actually, this was made even more condition-y in 3.8. Now we check __iter__ too:

D.update([E, ]**F) -> None.  Update D from dict/iterable E and F.
If E is present, has a .keys() method, is a subclass of dict, and hasn't overridden __iter__, then does:  for k in E: D[k] = E[k]
If E is present, has a .keys() method, and is not a subclass of dict or has overridden __iter__, then does:  for k in E.keys(): D[k] = E[k]
If E is present and lacks a .keys() method, then does:  for k, v in E: D[k] = v
In either case, this is followed by: for k in F:  D[k] = F[k]

Bleh.

On Tue, Mar 5, 2019 at 2:54 PM Brandt Bucher <brandtbucher@gmail.com> wrote:
Should our __sub__ behavior be the same...

Sorry, our "__isub__" behavior. Long day...

On Tue, Mar 5, 2019 at 2:47 PM Brandt Bucher <brandtbucher@gmail.com> wrote:
 These semantics are intended to match those of update as closely as possible. For the dict built-in itself, calling keys is redundant as iteration over a dict iterates over its keys; but for subclasses or other mappings, update prefers to use the keys method.
 
The above paragraph may be inaccurate. Although the dict docstring states that keys will be called if it exists, this does not seem to be the case for dict subclasses. Bug or feature?

>>> print(dict.update.__doc__)
D.update([E, ]**F) -> None.  Update D from dict/iterable E and F.
If E is present and has a .keys() method, then does:  for k in E: D[k] = E[k]
If E is present and lacks a .keys() method, then does:  for k, v in E: D[k] = v
In either case, this is followed by: for k in F:  D[k] = F[k]

It's actually pretty interesting... and misleading/wrongish. It never says that keys is *called*... in reality, it just checks for the "keys" method before deciding whether to proceed with PyDict_Merge or PyDict_MergeFromSeq2. It should really read more like:

D.update([E, ]**F) -> None.  Update D from dict/iterable E and F.
If E is present, has a .keys() method, and is a subclass of dict, then does:  for k in E: D[k] = E[k]
If E is present, has a .keys() method, and is not a subclass of dict, then does:  for k in E.keys(): D[k] = E[k]
If E is present and lacks a .keys() method, then does:  for k, v in E: D[k] = v
In either case, this is followed by: for k in F:  D[k] = F[k]

Should our __sub__ behavior be the same (i.e., iterate for dict subclasses and objects without "keys()", otherwise call "keys()" and iterate over that)? __iadd__ calls into this logic already. It seems to be the most "natural" solution here, if we desire behavior analogous to "update".

Brandt

On Fri, Mar 1, 2019 at 8:26 AM Steven D'Aprano <steve@pearwood.info> wrote:
Attached is a draft PEP on adding + and - operators to dict for
discussion.

This should probably go here:

https://github.com/python/peps

but due to technical difficulties at my end, I'm very limited in what I
can do on Github (at least for now). If there's anyone who would like to
co-author and/or help with the process, that will be appreciated.


--
Steven
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/