Re: [Python-ideas] PEP: Dict addition and subtraction

2019-03-01 Thread Steven D'Aprano
Executive summary:

- I'm going to argue for subclass-preserving behaviour;

- I'm not wedded to the idea that dict += should actually call the 
update method, so long as it has the same behaviour;

- __iadd__ has no need to return NotImplemented or type-check its 
argument.

Details below.


On Fri, Mar 01, 2019 at 04:10:44PM -0800, Brandt Bucher wrote:

[...]
> In your Python implementation samples from the PEP, dict subclasses will
> behave differently from how list subclasses do. List subclasses, without
> overrides, return *list* objects for bare "+" operations 

Right -- and I think they are wrong to do so, for reasons I explained 
here:

https://mail.python.org/pipermail/python-ideas/2019-March/055547.html

I think the standard handling of subclasses in Python builtins is wrong, 
and I don't wish to emulate that wrong behaviour without a really good 
reason. Or at least a better reason than "other methods break 
subclassing unless explicitly overloaded, so this should do so too".

Or at least not without a fight :-)



> (and "+=" won't call an overridden "extend" method).

I'm slightly less opinionated about that. Looking more closely into the 
docs, I see that they don't actually say that += calls list.extend:

s.extend(t)   extends s with the contents of t (for
or s += t the most part the same as s[len(s):len(s)] = t)

https://docs.python.org/3/library/stdtypes.html#mutable-sequence-types

only that they have the same effect. So the wording re lists calling 
extend certainly needs to be changed. But that doesn't mean that we must 
change the implementation. We have a choice:

- regardless of what lists do, we define += for dicts as literally 
  calling dict.update; the more I think about it, the less I like this.

- Or we say that += behaves similarly to update, without actually 
  calling the method. I think I prefer this.

(The second implies either that += either contains a duplicate of the 
update logic, or that += and update both delegate to a private, C-level 
function that does most of the work.)

I think that the second approach (define += as having the equivalent 
semantics of update but without actually calling the update method) is 
probably better. That decouples the two methods, allows subclasses to 
change one without necessarily changing the other.


> So a more analogous
> pseudo-implementation (if that's what we seek) would look like:
> 
> def __add__(self, other):
> if isinstance(other, dict):
> new = dict.copy(self)
> dict.update(new, other)
> return new
> return NotImplemented

We should not require the copy method.

The PEP should be more explicit that the approximate implementation does 
not imply the copy() and update() methods are actually called.


> def __iadd__(self, other):
> if isinstance(other, dict):
> dict.update(self, other)
> return self
> return NotImplemented

I don't agree with that implementation.

According to PEP 203, which introduced augmented assignment, the 
sequence of calls in ``d += e`` is:

1. Try to call ``d.__iadd__(e)``.

2. If __iadd__ is not present, try ``d.__add__(e)``.

3. If __add__ is missing too, try ``e.__radd__(d)``.

but my tests suggest this is inaccurate. I think the correct behaviour 
is this:

1. Try to call ``d.__iadd__(e)``.

2. If __iadd__ is not present, or if it returns NotImplemented, 
   try ``d.__add__(e)``.

3. If __add__ is missing too, or if it returns NotImplemented,
   fail with TypeError.

In other words, e.__radd__ is not used.

We don't want dict.__iadd__ to try calling __add__, since the later is 
more restrictive and less efficient than the in-place merge. So there is 
no need for __iadd__ to return NotImplemented. It should either succeed 
on its own, or fail hard:

def __iadd__(self, other):
self.update(other)
return self

Except that the actual C implementation won't call the update method 
itself, but will follow the same semantics.

See the docstring for dict.update for details of what is accepted by 
update.


-- 
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/


Re: [Python-ideas] PEP: Dict addition and subtraction

2019-03-01 Thread Neil Girdhar
I think that sequence should be fixed.

On Fri., Mar. 1, 2019, 7:12 p.m. Brandt Bucher, 
wrote:

> While working through my implementation, I've come across a couple of
> inconsistencies with the current proposal:
>
> > The merge operator will have the same relationship to the dict.update
> method as the list concatenation operator has to list.extend, with dict
> difference being defined analogously.
>
> I like this premise. += for lists *behaves* like extend, and += for dicts
> *behaves* like update.
>
> However, later in the PEP it says:
>
> > Augmented assignment will just call the update method. This is
> analogous to the way list += calls the extend method, which accepts any
> iterable, not just lists.
>
> In your Python implementation samples from the PEP, dict subclasses will
> behave differently from how list subclasses do. List subclasses, without
> overrides, return *list* objects for bare "+" operations (and "+=" won't
> call an overridden "extend" method). So a more analogous
> pseudo-implementation (if that's what we seek) would look like:
>
> def __add__(self, other):
> if isinstance(other, dict):
> new = dict.copy(self)
> dict.update(new, other)
> return new
> return NotImplemented
>
>  def __radd__(self, other):
> if isinstance(other, dict):
> new = dict.copy(other)
> dict.update(other, self)
> return new
> return NotImplemented
>
> def __iadd__(self, other):
> if isinstance(other, dict):
> dict.update(self, other)
> return self
> return NotImplemented
>
> This is what my C looks like right now. We can choose to update these 
> semantics to be "nicer" to subclasses, but I don't see any precedent for it 
> (lists, sets, strings, etc.).
>
> Brandt
>
>
> On Fri, Mar 1, 2019 at 11:41 AM Brett Cannon  wrote:
>
>>
>>
>> On Fri, Mar 1, 2019 at 8:50 AM Brandt Bucher 
>> wrote:
>>
>>> I’ve never been part of this process before, but I’m interested in
>>> learning and helping any way I can.
>>>
>>
>> Thanks!
>>
>>
>>>
>>> My addition implementation is attached to the bpo, and I’m working today
>>> on bringing it in line with the PEP in its current form (specifically,
>>> subtraction operations).
>>>
>>> https://github.com/python/cpython/pull/12088
>>>
>>
>> When your proposed patch is complete, Brandt, just ask Steven to update
>> the PEP to mention that there's a proposed implementation attached to the
>> issue tracking the idea.
>>
>> -Brett
>>
>>
>>>
>>>
>>> Brandt
>>>
>>> On Mar 1, 2019, at 08:26, Steven D'Aprano  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/
>>>
>>> ___
>>> Python-ideas mailing list
>>> Python-ideas@python.org
>>> https://mail.python.org/mailman/listinfo/python-ideas
>>> Code of Conduct: http://python.org/psf/codeofconduct/
>>>
>> --
>
> ---
> You received this message because you are subscribed to a topic in the
> Google Groups "python-ideas" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/python-ideas/jq5QVTt3CAI/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> python-ideas+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
> --
>
> ---
> You received this message because you are subscribed to a topic in the
> Google Groups "python-ideas" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/python-ideas/jq5QVTt3CAI/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> python-ideas+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP: Dict addition and subtraction

2019-03-01 Thread Brandt Bucher
While working through my implementation, I've come across a couple of
inconsistencies with the current proposal:

> The merge operator will have the same relationship to the dict.update
method as the list concatenation operator has to list.extend, with dict
difference being defined analogously.

I like this premise. += for lists *behaves* like extend, and += for dicts
*behaves* like update.

However, later in the PEP it says:

> Augmented assignment will just call the update method. This is analogous
to the way list += calls the extend method, which accepts any iterable, not
just lists.

In your Python implementation samples from the PEP, dict subclasses will
behave differently from how list subclasses do. List subclasses, without
overrides, return *list* objects for bare "+" operations (and "+=" won't
call an overridden "extend" method). So a more analogous
pseudo-implementation (if that's what we seek) would look like:

def __add__(self, other):
if isinstance(other, dict):
new = dict.copy(self)
dict.update(new, other)
return new
return NotImplemented

 def __radd__(self, other):
if isinstance(other, dict):
new = dict.copy(other)
dict.update(other, self)
return new
return NotImplemented

def __iadd__(self, other):
if isinstance(other, dict):
dict.update(self, other)
return self
return NotImplemented

This is what my C looks like right now. We can choose to update these
semantics to be "nicer" to subclasses, but I don't see any precedent
for it (lists, sets, strings, etc.).

Brandt


On Fri, Mar 1, 2019 at 11:41 AM Brett Cannon  wrote:

>
>
> On Fri, Mar 1, 2019 at 8:50 AM Brandt Bucher 
> wrote:
>
>> I’ve never been part of this process before, but I’m interested in
>> learning and helping any way I can.
>>
>
> Thanks!
>
>
>>
>> My addition implementation is attached to the bpo, and I’m working today
>> on bringing it in line with the PEP in its current form (specifically,
>> subtraction operations).
>>
>> https://github.com/python/cpython/pull/12088
>>
>
> When your proposed patch is complete, Brandt, just ask Steven to update
> the PEP to mention that there's a proposed implementation attached to the
> issue tracking the idea.
>
> -Brett
>
>
>>
>>
>> Brandt
>>
>> On Mar 1, 2019, at 08:26, Steven D'Aprano  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/
>>
>> ___
>> Python-ideas mailing list
>> Python-ideas@python.org
>> https://mail.python.org/mailman/listinfo/python-ideas
>> Code of Conduct: http://python.org/psf/codeofconduct/
>>
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Greg Ewing

Serhiy Storchaka wrote:
And this opens a non-easy problem: how to create a mapping of the same 
type?


That's the responsibility of the class implementing the + operator.

There doesn't have to be any guarantee that a subclass of it will
automatically return an instance of the subclass (many existing
types provide no such guarantee, e.g. + on strings), so whatever
strategy it uses doesn't have to be part of its public API.

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


Re: [Python-ideas] PEP: Dict addition and subtraction

2019-03-01 Thread Brett Cannon
On Fri, Mar 1, 2019 at 8:50 AM Brandt Bucher  wrote:

> I’ve never been part of this process before, but I’m interested in
> learning and helping any way I can.
>

Thanks!


>
> My addition implementation is attached to the bpo, and I’m working today
> on bringing it in line with the PEP in its current form (specifically,
> subtraction operations).
>
> https://github.com/python/cpython/pull/12088
>

When your proposed patch is complete, Brandt, just ask Steven to update the
PEP to mention that there's a proposed implementation attached to the issue
tracking the idea.

-Brett


>
>
> Brandt
>
> On Mar 1, 2019, at 08:26, Steven D'Aprano  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/
>
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Guido van Rossum
On Thu, Feb 28, 2019 at 10:30 PM Serhiy Storchaka 
wrote:

> 28.02.19 23:19, Greg Ewing пише:
> > Serhiy Storchaka wrote:
> >> I do not understand why we discuss a new syntax for dict merging if we
> >> already have a syntax for dict merging: {**d1, **d2} (which works with
> >> *all* mappings).
> >
> > But that always returns a dict. A '+' operator could be implemented
> > by other mapping types to return a mapping of the same type.
>
> And this opens a non-easy problem: how to create a mapping of the same
> type? Not all mappings, and even not all dict subclasses have a copying
> constructor.
>

There's a compromise solution for this possible. We already do this for
Sequence and MutableSequence: Sequence does *not* define __add__, but
MutableSequence *does* define __iadd__, and the default implementation just
calls self.update(other). I propose the same for Mapping (do nothing) and
MutableMapping: make the default __iadd__ implementation call
self.update(other).

Looking at the code for Counter, its __iadd__ and __add__ behave subtly
different than Counter.update(): __iadd__ and __add__ (and __radd__) drop
values that are <= 0, while update() does not. That's all fine -- Counter
is not bound by the exact same semantics as dict (starting with its
update() method, which adds values rather than overwriting).

Anyways, the main reason to prefer d1+d2 over {**d1, **d2} is that the
latter is highly non-obvious except if you've already encountered that
pattern before, while d1+d2 is what anybody familiar with other Python
collection types would guess or propose. And the default semantics for
subclasses of dict that don't override these are settled with the "d =
d1.copy(); d.update(d2)" equivalence.

-- 
--Guido van Rossum (python.org/~guido)
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP: Dict addition and subtraction

2019-03-01 Thread Guido van Rossum
Thanks -- FYI I renamed the file to .rst (per convention for PEPs in ReST
format) and folded long text lines.

On Fri, Mar 1, 2019 at 8:53 AM Eric V. Smith  wrote:

> Hi, Steven.
>
> I can help you with it. I added it as PEP 584. I had to add the PEP
> headers, but didn't do any other editing.
>
> I'm going to be out of town for the next 2 weeks, so I might be slow in
> responding.
>
> Eric
>
> On 3/1/2019 11:26 AM, Steven D'Aprano 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.
> >
> >
> >
> > ___
> > Python-ideas mailing list
> > Python-ideas@python.org
> > https://mail.python.org/mailman/listinfo/python-ideas
> > Code of Conduct: http://python.org/psf/codeofconduct/
> >
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>


-- 
--Guido van Rossum (python.org/~guido)
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP: Dict addition and subtraction

2019-03-01 Thread Neil Girdhar
Looks like a good start.

I think you should replace all of the lines:
 if isinstance(other, dict):
with
 if isinstance(self, type(other)):


Since if other is an instance of a dict subclass, he should be the one to 
process the addition. On the other hand, if self is an instance of the 
derived type, then we are free to do the combination.


I think you should also change this wording:


"the result type will be the type of the left operand"


since the result type will be negotiated between the operands (even in your 
implemenation).


__sub__ can be implemented more simply as a dict comprehension.


Don't forget to return self in __isub__ and __iadd__ or they won't work.


I think __isub__ would be simpler like this:

def __isub__(self, it):
 if it is self:
  self.clear()
 else:
  for value in it:
 del self[value]
 return self

I don't see why you would bother looking for keys (iter will do that 
anyway).




On Friday, March 1, 2019 at 11:27:54 AM UTC-5, Steven D'Aprano 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/


Re: [Python-ideas] PEP: Dict addition and subtraction

2019-03-01 Thread Eric V. Smith

Hi, Steven.

I can help you with it. I added it as PEP 584. I had to add the PEP 
headers, but didn't do any other editing.


I'm going to be out of town for the next 2 weeks, so I might be slow in 
responding.


Eric

On 3/1/2019 11:26 AM, Steven D'Aprano 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.



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


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


Re: [Python-ideas] PEP: Dict addition and subtraction

2019-03-01 Thread Brandt Bucher
I’ve never been part of this process before, but I’m interested in learning and 
helping any way I can.

My addition implementation is attached to the bpo, and I’m working today on 
bringing it in line with the PEP in its current form (specifically, subtraction 
operations).

https://github.com/python/cpython/pull/12088

Brandt

> On Mar 1, 2019, at 08:26, Steven D'Aprano  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/
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP: Dict addition and subtraction

2019-03-01 Thread INADA Naoki
> If the keys are not strings, it currently works in CPython, but it may not 
> work with other implementations, or future versions of CPython[2].

I don't think so.  https://bugs.python.org/issue35105 and
https://mail.python.org/pipermail/python-dev/2018-October/155435.html
are about kwargs.  I think non string keys are allowed for {**d1,
**d2} by language.

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


[Python-ideas] PEP: Dict addition and subtraction

2019-03-01 Thread Steven D'Aprano
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

==
PEP- Dict addition and subtraction
==

**DRAFT** -- This is a draft document for discussion.

Abstract


This PEP suggests adding merge ``+`` and difference ``-`` operators to the 
built-in ``dict`` class.

The merge operator will have the same relationship to the ``dict.update`` 
method as the list concatenation operator has to ``list.extend``, with dict 
difference being defined analogously.


Examples


Dict addition will return a new dict containing the left operand merged with 
the right operand.

>>> d = {'spam': 1, 'eggs': 2, 'cheese': 3}
>>> e = {'cheese': 'cheddar', 'aardvark': 'Ethel'}
>>> d + e
{'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}
>>> e + d
{'cheese': 3, 'aardvark': 'Ethel', 'spam': 1, 'eggs': 2}

The augmented assignment version operates in-place.

>>> d += e
>>> print(d)
{'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}

Analogously with list addition, the operator version is more restrictive, and 
requires that both arguments are dicts, while the augmented assignment version 
allows anything the ``update`` method allows, such as iterables of key/value 
pairs.

>>> d + [('spam', 999)]
Traceback (most recent call last):
  ...
TypeError: can only merge dict (not "list") to dict

>>> d += [('spam', 999)]
>>> print(d)
{'spam': 999, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}


Dict difference ``-`` will return a new dict containing the items from the left 
operand which are not in the right operand.

>>> d = {'spam': 1, 'eggs': 2, 'cheese': 3}
>>> e = {'cheese': 'cheddar', 'aardvark': 'Ethel'}
>>> d - e
{'spam': 1, 'eggs': 2}
>>> e - d
{'aardvark': 'Ethel'}

Augmented assignment will operate in place.

>>> d -= e
>>> print(d)
{'spam': 1, 'eggs': 2}


Like the merge operator and list concatenation, the difference operator 
requires both operands to be dicts, while the augmented version allows any 
iterable of keys.

>>> d - {'spam', 'parrot'}
Traceback (most recent call last):
  ...
TypeError: cannot take the difference of dict and set

>>> d -= {'spam', 'parrot'}
>>> print(d)
{'eggs': 2, 'cheese': 'cheddar'}

>>> d -= [('spam', 999)]
>>> print(d)
{'spam': 999, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}


Semantics
-

For the merge operator, if a key appears in both operands, the last-seen value 
(i.e. that from the right-hand operand) wins.  This shows that dict addition is 
not commutative, in general ``d + e`` will not equal ``e + d``.  This joins a 
number of other non-commutative addition operators among the builtins, 
including lists, tuples, strings and bytes.

Having the last-seen value wins makes the merge operator match the semantics of 
the ``update`` method, so that ``d + e`` is an operator version of 
``d.update(e)``.

The error messages shown above are not part of the API, and may change at any 
time.


Rejected semantics
~~

Rejected alternatives semantics for ``d + e`` include:

- Add only new keys from ``e``, without overwriting existing keys in ``d``.  
This may be done by reversing the operands  ``e + d``, or using dict difference 
first, ``d + (e - d)``.  The later is especially useful for the in-place 
version ``d += (e - d)``.

- Raise an exception if there are duplicate keys.  This seems unnecessarily 
restrictive and is not likely to be useful in practice.  For example, updating 
default configuration values with user-supplied values would most often fail 
under the requirement that keys are unique::

prefs = site_defaults + user_defaults + document_prefs

- Add the values of d2 to the corresponding values of d1.  This is the 
behaviour implemented by ``collections.Counter``.


Syntax
--

An alternative to the ``+`` operator is the pipe ``|`` operator, which is used 
for set union.  This suggestion did not receive much support on Python-Ideas.

The ``+`` operator was strongly preferred on Python-Ideas.[1]  It is more 
familiar than the pipe operator, matches nicely with ``-`` as a pair, and the 
Counter subclass already uses ``+`` for merging.


Current Alternatives


To create a new dict containing the merged items of two (or more) dicts, one 
can currently write::

{**d1, **d2}

but this is neither obvious nor easily discoverable. It is only guaranteed to 
work if the keys are all strings. If the keys are not strings, it currently 
works in CPython, but it may not 

Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Stefan Behnel
Rémi Lapeyre schrieb am 01.03.19 um 16:44:
> Le 1 mars 2019 à 16:04:47, Stefan Behnel a écrit:
>> I think the behaviour makes sense when you know how it's implemented (keys
>> are stored separately from values).
> 
> Is a Python user expected to know the implementation details of all mappings
> thought?

No, it just helps _me_ in explaining the behaviour to myself. Feel free to
look it up in the documentation if you prefer.


>> I would have been less surprised if the
>> keys had also been reordered, but well, this is how it is now in Py3.6+, so
>> this is how it's going to work also for the operator.
>>
>> No *additional* surprises here. ;)
> 
> There is never any surprises left once all details have been carefully worked
> out but having `+` for mappings make it looks like an easy operation whose
> meaning is non ambiguous and obvious.
> 
> I’m still not convinced that it the meaning is obvious, and gave an example
> in my other message where I think it could be ambiguous.

What I meant was that it's obvious in the sense that it is no new behaviour
at all. It just provides an operator for behaviour that is already there.

We are not discussing the current behaviour here. That ship has long sailed
with the release of Python 3.6 beta 1 back in September 2016. The proposal
that is being discussed here is the new operator.

Stefan

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


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread INADA Naoki
>
> OK, thanks for explaining! So more formally speaking, you want to say that 
> for other examples of '+' in Python
> x1 + y == x2 + y if and only if x1 == x2, while for the proposed '+' for 
> dicts there may be many different x_i such that
> x_i + y gives the same result.
>

It's bit different thank my mind.  I'm OK to violate " x1 + y == x2 +
y if and only if x1 == x2", if it's not
important for semantics of type of x1, x2, and y.
Mapping is defined by key: value pairs.  It's core part.  I don't want
to call operator losts key: value pair as "sum".
That's why I thought this proposal is more serious abuse of + operator.

By the way, in case of sequence, `len(a) + len(b) == len(a + b)`.  In
case of set, `len(a) + len(b) >= len(a | b)`.
Proposed operation looks similar to `set | set` than `seq + seq` in
this point of view.

I don't propose | than +.  I just mean difference between
dict.update() and seq+seq is not
smaller than difference between dict.update() and set|set.

If | seems not fit to this operation, + seems not fit to this operation too.

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


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Stefan Behnel
Eric V. Smith schrieb am 01.03.19 um 15:49:
> I understand Inada to be saying that each value on the LHS (as shown above)
> affects the result on the RHS. That's the case with addition of ints and
> other types, but not so with the proposed dict addition. As he says, the
> {a:1} doesn't affect the result. The result would be the same if this key
> wasn't present in the first dict, or if the key had a different value.
> 
> This doesn't bother me, personally.

+1

Stefan

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


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Ivan Levkivskyi
On Fri, 1 Mar 2019 at 14:50, Eric V. Smith  wrote:

> On 3/1/2019 9:38 AM, INADA Naoki wrote:
> > Sorry, I'm not good at English enough to explain my mental model.
> >
> > I meant no skip, no ignorance, no throw away.
> >
> > In case of 1+2=3, both of 1 and 2 are not skipped, ignored or thrown
> away.
> >
> > On the other hand, in case of {a:1, b:2}+{a:2}={a:2, b:2}, I feel {a:1}
> > is skipped, ignored, or thrown away.  I used "lost" to explain it.
> >
> > And I used "lossless" for "there is no lost".  Not for reversible.
> >
> > If it isn't understandable to you, please ignore me.
> >
> > I think Rémi’s comment is very similar to my thought.  Merging mapping
> > is more complex than concatenate sequence and it seems hard to call it
> > "sum".
>
> I understand Inada to be saying that each value on the LHS (as shown
> above) affects the result on the RHS. That's the case with addition of
> ints and other types, but not so with the proposed dict addition. As he
> says, the {a:1} doesn't affect the result. The result would be the same
> if this key wasn't present in the first dict, or if the key had a
> different value.
>
> This doesn't bother me, personally. I'm just trying to clarify.
>

OK, thanks for explaining! So more formally speaking, you want to say that
for other examples of '+' in Python
x1 + y == x2 + y if and only if x1 == x2, while for the proposed '+' for
dicts there may be many different x_i such that
x_i + y gives the same result.

This doesn't bother me either, since this is not a critical requirement for
addition. I would say this is rather a coincidence
than a conscious decision.

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


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Stefan Behnel
Rémi Lapeyre schrieb am 01.03.19 um 15:50:
> Le 1 mars 2019 à 15:41:52, Stefan Behnel a écrit:
> 
>> Rémi Lapeyre schrieb am 01.03.19 um 15:06:
>>> I’m having issues to understand the semantics of d1 + d2.
>>>
>>> I think mappings are more complicated than sequences it some things
>>> seems not obvious to me.
>>>
>>> What would be OrderedDict1 + OrderedDict2, in which positions would be
>>> the resulting keys, which value would be used if the same key is
>>> present in both?
>>
>> The only reasonable answer I can come up with is:
>>
>> 1) unique keys from OrderedDict1 are in the same order as before
>> 2) duplicate keys and new keys from OrderedDict2 come after the keys from
>> d1, in their original order in d2 since they replace keys in d1.
>>
>> Basically, the expression says: "take a copy of d1 and add the items from
>> d2 to it". That's exactly what you should get, whether the mappings are
>> ordered or not (and dict are ordered by insertion in Py3.6+).
> 
> Thanks Stefan for your feedback, unless I’m mistaken this does not work like
> Rhodri suggested, he said:
> 
> I can tell it's pretty straightforward:
> 
> d = d1 + d2 is equivalent to:
> 
> >>> d = d1.copy()
> >>> d.update(d2)
> 
> But doing this:
> 
> >>> d1 = OrderedDict({"a": 1, "b": 2, "c": 3})
> >>> d2 = OrderedDict({"d": 4, "b": 5})
> >>> d = d1.copy()
> >>> d.update(d2)
> >>> d
> OrderedDict([('a', 1), ('b', 5), ('c', 3), ('d', 4)])
> 
> It looks like that the semantics are either not straightforward or what you
> proposed is not the only reasonable answer. Am I missing something?

No, I was, apparently. In Py3.7:

  >>> d1 = {"a": 1, "b": 2, "c": 3}
  >>> d1
  {'a': 1, 'b': 2, 'c': 3}
  >>> d2 = {"d": 4, "b": 5}
  >>> d = d1.copy()
  >>> d.update(d2)
  >>> d
  {'a': 1, 'b': 5, 'c': 3, 'd': 4}

I think the behaviour makes sense when you know how it's implemented (keys
are stored separately from values). I would have been less surprised if the
keys had also been reordered, but well, this is how it is now in Py3.6+, so
this is how it's going to work also for the operator.

No *additional* surprises here. ;)

Stefan

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


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Eric V. Smith

On 3/1/2019 9:38 AM, INADA Naoki wrote:

Sorry, I'm not good at English enough to explain my mental model.

I meant no skip, no ignorance, no throw away.

In case of 1+2=3, both of 1 and 2 are not skipped, ignored or thrown away.

On the other hand, in case of {a:1, b:2}+{a:2}={a:2, b:2}, I feel {a:1} 
is skipped, ignored, or thrown away.  I used "lost" to explain it.


And I used "lossless" for "there is no lost".  Not for reversible.

If it isn't understandable to you, please ignore me.

I think Rémi’s comment is very similar to my thought.  Merging mapping 
is more complex than concatenate sequence and it seems hard to call it 
"sum".


I understand Inada to be saying that each value on the LHS (as shown 
above) affects the result on the RHS. That's the case with addition of 
ints and other types, but not so with the proposed dict addition. As he 
says, the {a:1} doesn't affect the result. The result would be the same 
if this key wasn't present in the first dict, or if the key had a 
different value.


This doesn't bother me, personally. I'm just trying to clarify.

Eric



Regards,


2019年3月1日(金) 23:19 Ivan Levkivskyi >:


On Fri, 1 Mar 2019 at 13:48, INADA Naoki mailto:songofaca...@gmail.com>> wrote:

 >
 >
 > Is that an invariant you expect to apply to other uses of the +
 > operator?
 >
 > py> x = -1
 > py> x <= (x + x)
 > False
 >
 > py> [999] <= ([1, 2, 3] + [999])
 > False
 >

Please calm down.  I meant each type implements "sum"
in semantics of the type, in lossless way.
What "lossless" means is changed by the semantics of the type.

-1 + -1 = -2 is sum in numerical semantics.  There are no loss.


TBH I don't understand what is lossless about numeric addition. What
is the definition of lossless?
Clearly some information is lost, since you can't uniquely restore
two numbers you add from the result.

Unless you define what lossless means, there will be just more
misunderstandings.

--
Ivan



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


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


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Dan Sommers

On 3/1/19 8:19 AM, Ivan Levkivskyi wrote:

On Fri, 1 Mar 2019 at 13:48, INADA Naoki  wrote:


>
>
> Is that an invariant you expect to apply to other uses of the +
> operator?
>
> py> x = -1
> py> x <= (x + x)
> False
>
> py> [999] <= ([1, 2, 3] + [999])
> False
>

Please calm down.  I meant each type implements "sum"
in semantics of the type, in lossless way.
What "lossless" means is changed by the semantics of the type.

-1 + -1 = -2 is sum in numerical semantics.  There are no loss.



TBH I don't understand what is lossless about numeric addition. What is the
definition of lossless?
Clearly some information is lost, since you can't uniquely restore two
numbers you add from the result.

Unless you define what lossless means, there will be just more
misunderstandings.


I don't mean to put words into anyone's mouth, but I think I
see what IDANA Naoki means:  in other cases of summation,
the result somehow includes or contains both operands.  In
the case of summing dicts, though, some of the operands are
"lost" in the process.

I'm sure that I'm nowhere near as prolific as many of the
members of this list, but I don't remember ever merging
dicts (and a quick grep of my Python source tree confirms
same), so I won't comment further on the actual issue at
hand.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Stefan Behnel
Rémi Lapeyre schrieb am 01.03.19 um 15:06:
> I’m having issues to understand the semantics of d1 + d2.
> 
> I think mappings are more complicated than sequences it some things
> seems not obvious to me.
> 
> What would be OrderedDict1 + OrderedDict2, in which positions would be
> the resulting keys, which value would be used if the same key is
> present in both?

The only reasonable answer I can come up with is:

1) unique keys from OrderedDict1 are in the same order as before
2) duplicate keys and new keys from OrderedDict2 come after the keys from
d1, in their original order in d2 since they replace keys in d1.

Basically, the expression says: "take a copy of d1 and add the items from
d2 to it". That's exactly what you should get, whether the mappings are
ordered or not (and dict are ordered by insertion in Py3.6+).


> What would be defaultdict1 + defaultdict2?

No surprises here, the result is a copy of defaultdict1 (using the same
missing-key function) with all items from defaultdict2 added.

Remember that the order of the two operands matters. The first always
defines the type of the result, the second is only added to it.


> It seems to me that subclasses of dict are complex mappings for which
> « merging » may be less obvious than for sequences.

It's the same for subclasses of sequences.

Stefan

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


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread INADA Naoki
Sorry, I'm not good at English enough to explain my mental model.

I meant no skip, no ignorance, no throw away.

In case of 1+2=3, both of 1 and 2 are not skipped, ignored or thrown away.

On the other hand, in case of {a:1, b:2}+{a:2}={a:2, b:2}, I feel {a:1} is
skipped, ignored, or thrown away.  I used "lost" to explain it.

And I used "lossless" for "there is no lost".  Not for reversible.

If it isn't understandable to you, please ignore me.

I think Rémi’s comment is very similar to my thought.  Merging mapping is
more complex than concatenate sequence and it seems hard to call it "sum".

Regards,


2019年3月1日(金) 23:19 Ivan Levkivskyi :

> On Fri, 1 Mar 2019 at 13:48, INADA Naoki  wrote:
>
>> >
>> >
>> > Is that an invariant you expect to apply to other uses of the +
>> > operator?
>> >
>> > py> x = -1
>> > py> x <= (x + x)
>> > False
>> >
>> > py> [999] <= ([1, 2, 3] + [999])
>> > False
>> >
>>
>> Please calm down.  I meant each type implements "sum"
>> in semantics of the type, in lossless way.
>> What "lossless" means is changed by the semantics of the type.
>>
>> -1 + -1 = -2 is sum in numerical semantics.  There are no loss.
>>
>
> TBH I don't understand what is lossless about numeric addition. What is
> the definition of lossless?
> Clearly some information is lost, since you can't uniquely restore two
> numbers you add from the result.
>
> Unless you define what lossless means, there will be just more
> misunderstandings.
>
> --
> Ivan
>
>
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Neil Girdhar


On Friday, March 1, 2019 at 5:47:06 AM UTC-5, Steven D'Aprano wrote:
>
> On Fri, Mar 01, 2019 at 08:47:36AM +0200, Serhiy Storchaka wrote: 
>
> > Currently Counter += dict works and Counter + dict is an error. With 
> > this change Counter + dict will return a value, but it will be different 
> > from the result of the += operator. 
>
> That's how list.__iadd__ works too: ListSubclass + list will return a 
> value, but it might not be the same as += since that operates in place 
> and uses a different dunder method. 
>
> Why is it a problem for dicts but not a problem for lists? 
>
>
> > Also, if the custom dict subclass implemented the plus operator with 
> > different semantic which supports the addition with a dict, this change 
> > will break it, because dict + CustomDict will call dict.__add__ instead 
> > of CustomDict.__radd__. 
>
> That's not how operators work in Python or at least that's not how they 
> worked the last time I looked: if the behaviour has changed without 
> discussion, that's a breaking change that should be reverted. 
>
> Obviously I can't show this with dicts, but here it is with lists: 
>
> py> class MyList(list): 
> ... def __radd__(self, other): 
> ... print("called subclass first") 
> ... return "Something" 
> ... 
> py> [1, 2, 3] + MyList() 
> called subclass first 
> 'Something' 
>
>
> This is normal, standard behaviour for Python operators: if the right 
> operand is a subclass of the left operand, the reflected method __r*__ 
> is called first. 
>
>
> > Adding support of new operators to builting 
> > types is dangerous. 
>
> Explain what makes new operators more dangerous than old operators 
> please. 
>
>
> > >I do not understand why we discuss a new syntax for dict merging if 
> we 
> > >already have a syntax for dict merging: {**d1, **d2} (which works 
> with 
> > >*all* mappings). Is not this contradicts the Zen? 
> > > 
> > > 
> > >But (as someone else pointed out) {**d1, **d2} always returns a dict, 
> > >not the type of d1 and d2. 
> > 
> > And this saves us from the hard problem of creating a mapping of the 
> > same type. 
>
> What's wrong with doing this? 
>
> new = type(self)() 
>
> Or the equivalent from C code. If that doesn't work, surely that's the 
> fault of the subclass, the subclass is broken, and it will raise an 
> exception. 
>
> I don't think it is our responsibility to do anything more than call 
> the subclass constructor. If that's broken, then so be it. 
>
>
> Possibly relevant: I've always been frustrated and annoyed at classes 
> that hardcode their own type into methods. E.g. something like: 
>
> class X: 
> def spam(self, arg): 
> return X(eggs)   
> # Wrong! Bad! Please use type(self) instead. 
>
> That means that each subclass has to override every method: 
>
> class MySubclass(X): 
> def spam(self, arg): 
> # Do nothing except change the type returned. 
> return type(self)( super().spam(arg) ) 
>
>
> This gets really annoying really quickly. Try subclassing int, for 
> example, where you have to override something like 30+ methods and do 
> nothing but wrap calls to super. 
>

I agree with you here.  You might want to start a different thread with 
this idea and possibly come up with a PEP.  There might be some pushback 
for efficiency's sake, so you might have to reel in your proposal to 
collections.abc mixin methods and UserDict methods.

Regarding the proposal, I agree with the reasoning put forward by Guido and 
I like it.  I think there should be:
* d1 + d2
* d1 += d2
* d1 - d2
* d1 -= d2

which are roughly (ignoring steve's point about types)
* {**d1, **d2}
* d1.update(d2)
* {k: v for k, v in d1.items() if k not in d2}
* for k in list(d1): if k not in d2: del d1[k]

Seeing this like this, there should be no confusion about what the 
operators do.

I understand the points people made about the Zen of Python.  However, I 
think that just like with lists, we tend to use l1+l2 when combining lists 
and [*l1, x, *l2, y] when combining lists and elements.  Similarly, I think 
{**d1, **d2} should only be written when there are also key value pairs, 
like {**d1, k: v, **d2, k2: v2}.

Best,

Neil


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


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Rhodri James

On 01/03/2019 14:06, Rémi Lapeyre wrote:

I’m having issues to understand the semantics of d1 + d2.


That's understandable, clouds of confusion have been raised.  As far as 
I can tell it's pretty straightforward: d = d1 + d2 is equivalent to:


>>> d = d1.copy()
>>> d.update(d2)

All of your subsequent questions then become "What does 
DictSubclassInQuestion.update() do?" which should be well defined.



--
Rhodri James *-* Kynesim Ltd
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Ivan Levkivskyi
On Fri, 1 Mar 2019 at 13:48, INADA Naoki  wrote:

> >
> >
> > Is that an invariant you expect to apply to other uses of the +
> > operator?
> >
> > py> x = -1
> > py> x <= (x + x)
> > False
> >
> > py> [999] <= ([1, 2, 3] + [999])
> > False
> >
>
> Please calm down.  I meant each type implements "sum"
> in semantics of the type, in lossless way.
> What "lossless" means is changed by the semantics of the type.
>
> -1 + -1 = -2 is sum in numerical semantics.  There are no loss.
>

TBH I don't understand what is lossless about numeric addition. What is the
definition of lossless?
Clearly some information is lost, since you can't uniquely restore two
numbers you add from the result.

Unless you define what lossless means, there will be just more
misunderstandings.

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


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Rémi Lapeyre
I’m having issues to understand the semantics of d1 + d2.

I think mappings are more complicated than sequences it some things
seems not obvious to me.

What would be OrderedDict1 + OrderedDict2, in which positions would be
the resulting keys, which value would be used if the same key is
present in both?

What would be defaultdict1 + defaultdict2?

It seems to me that subclasses of dict are complex mappings for which
« merging » may be less obvious than for sequences.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread INADA Naoki
>
>
> Is that an invariant you expect to apply to other uses of the +
> operator?
>
> py> x = -1
> py> x <= (x + x)
> False
>
> py> [999] <= ([1, 2, 3] + [999])
> False
>

Please calm down.  I meant each type implements "sum"
in semantics of the type, in lossless way.
What "lossless" means is changed by the semantics of the type.

-1 + -1 = -2 is sum in numerical semantics.  There are no loss.

[1, 2, 3] + [999] = [1, 2, 3, 999] is (lossless) sum in sequence semantics.

So what about {"a": 1} + {"a": 2}.  Is there (lossless) sum in dict semantics?

* {"a": 1} -- It seems {"a": 2} is lost in dict semantics.  Should it
really called "sum" ?
* {"a": 2} -- It seems {"a": 1} is lost in dict semantics.  Should it
really called "sum" ?
* {"a": 3} -- It seems bit curious compared with + of sequence,
because [2]+[3] is not [5].
   It looks like more Counter than container.
* ValueError -- Hmm, it looks ugly to me.

So I don't think "sum" is not fit to dict semantics.

Regards,
-- 
INADA Naoki  
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread INADA Naoki
On Fri, Mar 1, 2019 at 10:10 PM Steven D'Aprano  wrote:
>
> On Fri, Mar 01, 2019 at 08:59:45PM +0900, INADA Naoki wrote:
> > I dislike adding more operator overload to builtin types.
> >
> > str is not commutative, but it satisfies a in (a+b), and b in (a+b).
> > There are no loss.
>
> Is this an invariant you expect to apply for other classes that support
> the addition operator?
>
> 5 in (5 + 6)

I meant more high level semantics: "no loss".  Not only "in".
So my example about set used "<=" operator.

5 + 6 is sum of 5 and 6.

>
> [1, 2, 3] in ([1, 2, 3] + [4, 5, 6])
>

Both of [1,2,3] and [4,5,6] are not lost in result.

>
> Since it doesn't apply for int, float, complex, list or tuple, why do
> you think it must apply to dicts?
>

You misunderstood my "no loss" expectation.


>
> > In case of dict + dict, it not only sum.  There may be loss value.
>
> Yes? Why is that a problem?
>

It's enough reason to I dislike.

>
> >{"a":1} + {"a":2} = ?
>
> Would you like to argue that Counter.__add__ is a mistake for the same
> reason?
>

In Counter's case, it's clear.  In case of dict, it's unclear.

> Counter(('a', 1)) + Counter(('a', 2)) = ?
>
>
> For the record, what I expected the above to do turned out to be
> *completely wrong* when I tried it. I expected Counter({'a': 3}) but the
> actual results are Counter({'a': 2, 1: 1, 2: 1}).

It just because you misunderstood Counter's initializer argument.
It's not relating to how overload + or | operator.

>
> Every operation is going to be mysterious if you have never
> learned what it does:
>
> from array import array
> a = array('i', [1, 2, 3])
> b = array('i', [10, 20, 30])
> a + b = ?
>
> Without trying it or reading the docs, should that be an
> error, or concatenation, or element-wise addition?
>

I never say every operator must be expected by everyone.
Don't straw man.


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


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Steven D'Aprano
On Fri, Mar 01, 2019 at 09:58:08PM +0900, INADA Naoki wrote:

> >>> {1} <= ({1} | {1.0})
> True
> >>> {1.0} <= ({1} | {1.0})
> True
> 
> So dict + dict is totally different than set | set.
> dict + dict has los at equality level.


Is that an invariant you expect to apply to other uses of the + 
operator?

py> x = -1
py> x <= (x + x)
False

py> [999] <= ([1, 2, 3] + [999])
False



-- 
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/


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Steven D'Aprano
On Fri, Mar 01, 2019 at 08:59:45PM +0900, INADA Naoki wrote:
> I dislike adding more operator overload to builtin types.
> 
> str is not commutative, but it satisfies a in (a+b), and b in (a+b).
> There are no loss.

Is this an invariant you expect to apply for other classes that support 
the addition operator?

5 in (5 + 6)

[1, 2, 3] in ([1, 2, 3] + [4, 5, 6])


Since it doesn't apply for int, float, complex, list or tuple, why do 
you think it must apply to dicts?


> In case of dict + dict, it not only sum.  There may be loss value.

Yes? Why is that a problem?


>{"a":1} + {"a":2} = ?

Would you like to argue that Counter.__add__ is a mistake for the same 
reason?

Counter(('a', 1)) + Counter(('a', 2)) = ?


For the record, what I expected the above to do turned out to be 
*completely wrong* when I tried it. I expected Counter({'a': 3}) but the 
actual results are Counter({'a': 2, 1: 1, 2: 1}).

Every operation is going to be mysterious if you have never 
learned what it does:

from array import array
a = array('i', [1, 2, 3])
b = array('i', [10, 20, 30])
a + b = ?

Without trying it or reading the docs, should that be an 
error, or concatenation, or element-wise addition?


> In case of a.update(b), it's clear that b wins.

It wasn't clear to me when I was a beginner and first came across 
dict.update. I had to learn what it did by experimenting with manual 
loops until it made sense to me.


> In case of a + b, "which wins" or "exception raised on duplicated key?" is
> unclear to me.

Many things are unclear to me too. That doesn't make them any less 
useful.



-- 
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/


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Chris Angelico
On Fri, Mar 1, 2019 at 11:00 PM INADA Naoki  wrote:
>
> I dislike adding more operator overload to builtin types.
>
> str is not commutative, but it satisfies a in (a+b), and b in (a+b).
> There are no loss.
>
> In case of dict + dict, it not only sum.  There may be loss value.
>
>{"a":1} + {"a":2} = ?
>
> In case of a.update(b), it's clear that b wins.
> In case of a + b, "which wins" or "exception raised on duplicated key?" is 
> unclear to me.

Picking semantics can be done as part of the PEP discussion, and
needn't be a reason for rejecting the proposal before it's even made.
We have at least one other precedent to consider:

>>> {1} | {1.0}
{1}
>>> {1.0} | {1}
{1.0}

I have absolutely no doubt that these kinds of questions will be
thoroughly hashed out (multiple times, even) before the PEP gets to
pronouncement.

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


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread INADA Naoki
I dislike adding more operator overload to builtin types.

str is not commutative, but it satisfies a in (a+b), and b in (a+b).
There are no loss.

In case of dict + dict, it not only sum.  There may be loss value.

   {"a":1} + {"a":2} = ?

In case of a.update(b), it's clear that b wins.
In case of a + b, "which wins" or "exception raised on duplicated key?" is
unclear to me.

Regards,

On Thu, Feb 28, 2019 at 1:28 AM João Matos  wrote:

> Hello,
>
> I would like to propose that instead of using this (applies to Py3.5 and
> upwards)
> dict_a = {**dict_a, **dict_b}
>
> we could use
> dict_a = dict_a + dict_b
>
> or even better
> dict_a += dict_b
>
>
> Best regards,
>
> João Matos
>
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>


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


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Steven D'Aprano
On Thu, Feb 28, 2019 at 07:40:25AM -0500, James Lu wrote:

> I agree with Storchaka here. The advantage of existing dict merge 
> syntax is that it will cause an error if the object is not a dict or 
> dict-like object, thus preventing people from doing bad things.

What sort of "bad things" are you afraid of?


-- 
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/


Re: [Python-ideas] Add a "week" function or attribute to datetime.date

2019-03-01 Thread Robert Vanden Eynde
Currently one can do week = d.isocalendar()[1]

The iso definition of a week number has some nice properties.

robertvandeneynde.be

On Fri, 1 Mar 2019, 11:44 Antonio Galán,  wrote:

> The week number is usually refered to the week of the year, but the week
> of the month is also interesting, for example for some holiday which depend
> on the week number of the month, so in analogy with "weekday" we can use
> "yearweek" and "monthweek"
> El vie., 1 de marzo de 2019 9:33, Adrien Ricocotam 
> escribió:
>
>> I like the idea. But how to distinguish it from the number of week past
>> since the beginning of the month ?
>>
>> But that’s great.
>>
>> On Fri 1 Mar 2019 at 09:31, Antonio Galán  wrote:
>>
>>> Hi, datetime.date.today() (or other day)  has attributes .year and
>>> .month wich return the year and the month of that date, also it has a
>>> function weekday() wich return the number of the day in the week.
>>>
>>> I think it is a good idea add a function or attribute "week" wich return
>>> the number of the week on the year. It is useful to execute scripts once a
>>> week for example.
>>> ___
>>> Python-ideas mailing list
>>> Python-ideas@python.org
>>> https://mail.python.org/mailman/listinfo/python-ideas
>>> Code of Conduct: http://python.org/psf/codeofconduct/
>>>
>> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Steven D'Aprano
On Fri, Mar 01, 2019 at 08:47:36AM +0200, Serhiy Storchaka wrote:

> Currently Counter += dict works and Counter + dict is an error. With 
> this change Counter + dict will return a value, but it will be different 
> from the result of the += operator.

That's how list.__iadd__ works too: ListSubclass + list will return a 
value, but it might not be the same as += since that operates in place 
and uses a different dunder method.

Why is it a problem for dicts but not a problem for lists?


> Also, if the custom dict subclass implemented the plus operator with 
> different semantic which supports the addition with a dict, this change 
> will break it, because dict + CustomDict will call dict.__add__ instead 
> of CustomDict.__radd__.

That's not how operators work in Python or at least that's not how they 
worked the last time I looked: if the behaviour has changed without 
discussion, that's a breaking change that should be reverted.

Obviously I can't show this with dicts, but here it is with lists:

py> class MyList(list):
... def __radd__(self, other):
... print("called subclass first")
... return "Something"
...
py> [1, 2, 3] + MyList()
called subclass first
'Something'


This is normal, standard behaviour for Python operators: if the right 
operand is a subclass of the left operand, the reflected method __r*__ 
is called first.


> Adding support of new operators to builting 
> types is dangerous.

Explain what makes new operators more dangerous than old operators 
please.


> >I do not understand why we discuss a new syntax for dict merging if we
> >already have a syntax for dict merging: {**d1, **d2} (which works with
> >*all* mappings). Is not this contradicts the Zen?
> >
> >
> >But (as someone else pointed out) {**d1, **d2} always returns a dict, 
> >not the type of d1 and d2.
> 
> And this saves us from the hard problem of creating a mapping of the 
> same type.

What's wrong with doing this?

new = type(self)()

Or the equivalent from C code. If that doesn't work, surely that's the 
fault of the subclass, the subclass is broken, and it will raise an 
exception.

I don't think it is our responsibility to do anything more than call 
the subclass constructor. If that's broken, then so be it.


Possibly relevant: I've always been frustrated and annoyed at classes 
that hardcode their own type into methods. E.g. something like:

class X:
def spam(self, arg):
return X(eggs)  
# Wrong! Bad! Please use type(self) instead.

That means that each subclass has to override every method:

class MySubclass(X):
def spam(self, arg):
# Do nothing except change the type returned.
return type(self)( super().spam(arg) )


This gets really annoying really quickly. Try subclassing int, for 
example, where you have to override something like 30+ methods and do 
nothing but wrap calls to super.


-- 
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/


Re: [Python-ideas] Add a "week" function or attribute to datetime.date

2019-03-01 Thread Antonio Galán
The week number is usually refered to the week of the year, but the week of
the month is also interesting, for example for some holiday which depend on
the week number of the month, so in analogy with "weekday" we can use
"yearweek" and "monthweek"
El vie., 1 de marzo de 2019 9:33, Adrien Ricocotam 
escribió:

> I like the idea. But how to distinguish it from the number of week past
> since the beginning of the month ?
>
> But that’s great.
>
> On Fri 1 Mar 2019 at 09:31, Antonio Galán  wrote:
>
>> Hi, datetime.date.today() (or other day)  has attributes .year and .month
>> wich return the year and the month of that date, also it has a function
>> weekday() wich return the number of the day in the week.
>>
>> I think it is a good idea add a function or attribute "week" wich return
>> the number of the week on the year. It is useful to execute scripts once a
>> week for example.
>> ___
>> Python-ideas mailing list
>> Python-ideas@python.org
>> https://mail.python.org/mailman/listinfo/python-ideas
>> Code of Conduct: http://python.org/psf/codeofconduct/
>>
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Dict joining using + and +=

2019-03-01 Thread Ivan Levkivskyi
On Thu, 28 Feb 2019 at 07:18, Serhiy Storchaka  wrote:

> [...]
>
> I do not understand why we discuss a new syntax for dict merging if we
> already have a syntax for dict merging: {**d1, **d2} (which works with
> *all* mappings). Is not this contradicts the Zen?
>

FWIW there are already three ways for lists/sequences:

[*x, *y]
x + y
x.extend(y)  # in-place version

We already have first and third for dicts/mappings, I don't see a big
problem in adding a + for dicts,
also this is not really a new syntax, just implementing couple dunders for
a builtin class.

So I actually like this idea.

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


[Python-ideas] Add a "week" function or attribute to datetime.date

2019-03-01 Thread Antonio Galán
Hi, datetime.date.today() (or other day)  has attributes .year and .month
wich return the year and the month of that date, also it has a function
weekday() wich return the number of the day in the week.

I think it is a good idea add a function or attribute "week" wich return
the number of the week on the year. It is useful to execute scripts once a
week for example.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/