[Python-Dev] Re: PEP 584: Add Union Operators To dict

2020-02-06 Thread Brandt Bucher
> > We already have an API for copying a dict (dict.copy). I still fail to see 
> > problem with using a method that doesn't start and end with underscores, 
> > other than that we "haven't done it".
>
> Before Python 3.0, iterators had a next() method, and that was explicitly and 
> consciously changed to __next__(). The arguments there seem relevant here too.

Thanks for bringing this up. PEP 3114 does a great job of explaining how and 
why Python uses dunders for *language-level* constructs. I would probably be 
opposed to language features or built-in functions doing magical things with 
the `copy` method of dicts; however, in this case, it's being used by the dict 
itself! As the PEP 3114 says:

> In Python, double underscores before and after a name are used to distinguish 
> names that belong to the language itself... Not all things that are called 
> "protocols" are made of methods with double-underscore names... even though 
> the read method is part of the file protocol, it does not have double 
> underscores because there is no language construct that implicitly invokes 
> x.read().

The language itself doesn't call `copy`, but `dict` should feel free to. 
Especially if it makes life easier for subclasses (which PEP 584 actually 
encourages users to make in the "Rejected Semantics" section: 
https://www.python.org/dev/peps/pep-0584/#rejected-semantics)!
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/FIPVZTUM4CJ5WJWAAYGS4E55Y7AP7J6E/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Clarification of unpacking semantics.

2020-02-06 Thread Guido van Rossum
How did we move from [*a,...] to print(*a,...)? They are quite different.

On Thu, Feb 6, 2020 at 14:07 Serhiy Storchaka  wrote:

> 06.02.20 08:28, Brandt Bucher пише:
> > Commits 13bc139 and 8a4cd70 introduced subtle changes in the evaluation
> logic of unpacking operations. Previously, all elements were evaluated
> prior to being collected in a container. Now, these operations are
> interleaved. For example, the code `[*a, *b]` used to evaluate in the order
> `a` -> `b` -> `a.__iter__()` -> `b.__iter__()`. Now, it evaluates as `a` ->
> `a.__iter__()` -> `b` -> `b.__iter__()`.
> >
> > I believe this breaking semantic change is a bug, and I've opened a PR
> to fix it (https://github.com/python/cpython/pull/18264). My reasoning is
> that "unary *" isn't an operator; it doesn't appear on the operator
> precedence table in the docs, and you can't evaluate `*x`. Like the
> brackets and the comma, it's part of the syntax of the outer display
> expression, not the inner one. It specifies how the list should be built,
> so it should be evaluated last, as part of the list construction. And it
> has always been this way since PEP 448 (as far as I can tell).
> >
> > The docs themselves seem to support this line of reasoning (
> https://docs.python.org/3/reference/expressions.html#evaluation-order):
> >
> >> In the following lines, expressions will be evaluated in the arithmetic
> order of their suffixes:
> >> ...
> >> expr1(expr2, expr3, *expr4, **expr5)
> >
> > Note that the stars are not part of expressions 1-5, but are a part of
> the top-level call expression that operates on them all.
> >
> > Mark Shannon disagrees with me (I'll let him reply rather than attempt
> to summarize his argument for him), but we figured it might be better to
> get more input here on exactly whether you all think the behavior should
> change or not. You can see the discussion on the PR itself for some
> additional points and context.
>
> I have two problems with this change.
>
> 1. It changes error messages.
>
>  >>> print(*1)
> Traceback (most recent call last):
>File "", line 1, in 
> TypeError: print() argument after * must be an iterable, not int
>  >>> print(*1, *2)
> Traceback (most recent call last):
>File "", line 1, in 
> TypeError: Value after * must be an iterable, not int
>
> In 3.8 you got the same error message.
>
>  >>> print(*1)
> Traceback (most recent call last):
>File "", line 1, in 
> TypeError: print() argument after * must be an iterable, not int
>  >>> print(*1, *2)
> Traceback (most recent call last):
>File "", line 1, in 
> TypeError: print() argument after * must be an iterable, not int
>
> I am not sure whether the function name is a useful information, but
> some effort was spend to preserve it. In any case, error messages should
> be consistent.
>
>
> 2. It introduces performance regression.
>
> In 3.8 the bytecode for `(*a, *b, *c)` was:
>
>1   0 LOAD_NAME0 (a)
>2 LOAD_NAME1 (b)
>4 LOAD_NAME2 (c)
>6 BUILD_TUPLE_UNPACK   3
>
> In master it is:
>
>1   0 BUILD_LIST   0
>2 LOAD_NAME0 (a)
>4 LIST_EXTEND  1
>6 LOAD_NAME1 (b)
>8 LIST_EXTEND  1
>   10 LOAD_NAME2 (c)
>   12 LIST_EXTEND  1
>   14 LIST_TO_TUPLE
>
> The bytecode is larger, therefore slower. It also prevents possible
> optimization of BUILD_TUPLE_UNPACK and similar opcodes for common case
> of tuples and lists which would allow to minimize the number of memory
> allocations.
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/CZZKWFW22TBJ5VLO7GUIF7A7QBFTBAC2/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
-- 
--Guido (mobile)
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/PVCX2G6FJFCTW2P7D27UM76AAGSDJAT3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 584: Add Union Operators To dict

2020-02-06 Thread Paul G
I don't have a terribly strong opinion about whether or not it is acceptable to 
use dict.copy, my point was that the desired semantics can be achieved using 
only dunder methods if desired, and I think at this point getting the semantics 
right probably matters more than the implementation details. If we all agree on 
the semantics and we're just trying to decide how to get there, then I suppose 
I don't have a dog in the fight.

I will note that it doesn't seem to be true that operators never call standard 
methods. Looks like date.__add__ calls date.toordinal and date.fromordinal (at 
least in the pure Python implementation), and datetime calls those plus 
tzinfo.utcoffset. Not sure if the rule Serhiy is citing is only intended to 
apply to builtins, though.

On February 6, 2020 10:25:52 PM UTC, Brandt Bucher  
wrote:
>Sorry Paul, I sent my reply too soon.
>
>I see what you're saying, and I'm pretty firmly -1 on reinventing (or
>importing) copy.copy. We already have an API for copying a dict
>(dict.copy). 
>
>I still fail to see problem with using a method that doesn't start and
>end with underscores, other than that we "haven't done it".
>
>Brandt
>___
>Python-Dev mailing list -- python-dev@python.org
>To unsubscribe send an email to python-dev-le...@python.org
>https://mail.python.org/mailman3/lists/python-dev.python.org/
>Message archived at
>https://mail.python.org/archives/list/python-dev@python.org/message/7TQI54BEUN6GERZA3Y2GCXPBD3CHXKM6/
>Code of Conduct: http://python.org/psf/codeofconduct/
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/SCDWUIQX4ZLLU72QI4PYEG25W6JVIBFT/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 584: Add Union Operators To dict

2020-02-06 Thread Chris Angelico
On Fri, Feb 7, 2020 at 9:30 AM Brandt Bucher  wrote:
>
> Sorry Paul, I sent my reply too soon.
>
> I see what you're saying, and I'm pretty firmly -1 on reinventing (or 
> importing) copy.copy. We already have an API for copying a dict (dict.copy).
>
> I still fail to see problem with using a method that doesn't start and end 
> with underscores, other than that we "haven't done it".
>

Before Python 3.0, iterators had a next() method, and that was
explicitly and consciously changed to __next__(). The arguments there
seem relevant here too.

https://www.python.org/dev/peps/pep-3114/

ChrisA
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/SGWZHDDSMZEH53N2MK2MSY7UQPG543FU/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 584: Add Union Operators To dict

2020-02-06 Thread Brandt Bucher
Sorry Paul, I sent my reply too soon.

I see what you're saying, and I'm pretty firmly -1 on reinventing (or 
importing) copy.copy. We already have an API for copying a dict (dict.copy). 

I still fail to see problem with using a method that doesn't start and end with 
underscores, other than that we "haven't done it".

Brandt
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/7TQI54BEUN6GERZA3Y2GCXPBD3CHXKM6/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 584: Add Union Operators To dict

2020-02-06 Thread Brandt Bucher
> but I think the desired semantics can all be achieved using only magic 
> methods on the objects themselves

Hm. So, just to clarify, you're suggesting we use `__copy__`, if it exists? 
Interesting...
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/ZEB2VAVPGWHL6B55UAMYYQRALLILGQLE/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 584: Add Union Operators To dict

2020-02-06 Thread Paul Ganssle
On 2/6/20 4:23 PM, Serhiy Storchaka wrote:
> It would create an exception of two rules:
>
> 1. Operators on subclasses of builtin classes do not depend on
> overridden methods of arguments (except the corresponding dunder
> method). `list.__add__` and `set.__or__` do not call copy() and
> extend()/update(). You should override the corresponding dunder method
> to change the behavior of the operator.
>
> 2. Operators do not depend on non-dunder methods.
>
> This looks to me as a direct violation of the principle "Special cases
> aren't special enough to break the rules."
>
I may not fully understand the implications of #1, but I would think you
could implement the semantics Brandt wants using only dunder methods and
copy.copy (which itself dispatches to one of a number of dunder methods
- __copy__, __reduce__, __setstate__, depending on which ones are
defined - we could presumably avoid the `copy` import by partially
porting that logic into `__or__`):

def __or__(self, other):
    new_value = copy.copy(self)
    for key in other.__keys__():
    new_value.__setitem__(key, other.__getitem__(key))
    return new_value

Obviously the actual implementation would be in C and handle more edge
cases and whatnot, but I think the desired semantics can all be achieved
using only magic methods on the objects themselves (though we'd probably
want to bypass all that stuff in favor of a "fast path" in the case of
`dict` | `dict`).

Best,
Paul




signature.asc
Description: OpenPGP digital signature
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/QXLOQ6QZLF35FGCTTARFSUBNGK4U22MB/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Clarification of unpacking semantics.

2020-02-06 Thread Guido van Rossum
Then there’s nothing to do here right? Or just add it to whatsnew?

On Thu, Feb 6, 2020 at 13:20 Brandt Bucher  wrote:

> > We should fix that (by reverting to 3.8.1 behaviour) before 3.8.2 gets
> released.
>
> The commits which changed the behavior were bytecode/compiler changes that
> only went to master. I don't think they are present on any other branches.
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/GC3PGIGXFY47RQVOA4HLE3VX5IQ2VGTB/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
-- 
--Guido (mobile)
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/R6X4FROFYY5VG6VRSRHQ25PLMBUGXNA3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Clarification of unpacking semantics.

2020-02-06 Thread Serhiy Storchaka

06.02.20 08:28, Brandt Bucher пише:

Commits 13bc139 and 8a4cd70 introduced subtle changes in the evaluation logic of unpacking 
operations. Previously, all elements were evaluated prior to being collected in a container. Now, 
these operations are interleaved. For example, the code `[*a, *b]` used to evaluate in the order 
`a` -> `b` -> `a.__iter__()` -> `b.__iter__()`. Now, it evaluates as `a` -> 
`a.__iter__()` -> `b` -> `b.__iter__()`.

I believe this breaking semantic change is a bug, and I've opened a PR to fix it 
(https://github.com/python/cpython/pull/18264). My reasoning is that "unary *" 
isn't an operator; it doesn't appear on the operator precedence table in the docs, and 
you can't evaluate `*x`. Like the brackets and the comma, it's part of the syntax of the 
outer display expression, not the inner one. It specifies how the list should be built, 
so it should be evaluated last, as part of the list construction. And it has always been 
this way since PEP 448 (as far as I can tell).

The docs themselves seem to support this line of reasoning 
(https://docs.python.org/3/reference/expressions.html#evaluation-order):


In the following lines, expressions will be evaluated in the arithmetic order 
of their suffixes:
...
expr1(expr2, expr3, *expr4, **expr5)


Note that the stars are not part of expressions 1-5, but are a part of the 
top-level call expression that operates on them all.

Mark Shannon disagrees with me (I'll let him reply rather than attempt to 
summarize his argument for him), but we figured it might be better to get more 
input here on exactly whether you all think the behavior should change or not. 
You can see the discussion on the PR itself for some additional points and 
context.


I have two problems with this change.

1. It changes error messages.

>>> print(*1)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: print() argument after * must be an iterable, not int
>>> print(*1, *2)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: Value after * must be an iterable, not int

In 3.8 you got the same error message.

>>> print(*1)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: print() argument after * must be an iterable, not int
>>> print(*1, *2)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: print() argument after * must be an iterable, not int

I am not sure whether the function name is a useful information, but 
some effort was spend to preserve it. In any case, error messages should 
be consistent.



2. It introduces performance regression.

In 3.8 the bytecode for `(*a, *b, *c)` was:

  1   0 LOAD_NAME0 (a)
  2 LOAD_NAME1 (b)
  4 LOAD_NAME2 (c)
  6 BUILD_TUPLE_UNPACK   3

In master it is:

  1   0 BUILD_LIST   0
  2 LOAD_NAME0 (a)
  4 LIST_EXTEND  1
  6 LOAD_NAME1 (b)
  8 LIST_EXTEND  1
 10 LOAD_NAME2 (c)
 12 LIST_EXTEND  1
 14 LIST_TO_TUPLE

The bytecode is larger, therefore slower. It also prevents possible 
optimization of BUILD_TUPLE_UNPACK and similar opcodes for common case 
of tuples and lists which would allow to minimize the number of memory 
allocations.

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/CZZKWFW22TBJ5VLO7GUIF7A7QBFTBAC2/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 584: Add Union Operators To dict

2020-02-06 Thread Brandt Bucher
> It would create an exception of two rules:

I don't think these are "rules", I think they're just "the way things are".

If I'm subclassing `dict`, and I see in the docs something to the effect of:

> By default, `dict` subclasses will return `dict` objects for `|` operations. 
> To force the creation of a new instance of the subclass, users can override 
> the `copy` method. In that case, the return value from this method will be 
> used instead.

Then my life suddenly becomes a lot better, because chances are I've already 
thought to override `copy`. And if I want the "legacy" behavior, it's as simple 
as not bothering with "copy" (or, if I need to, overriding the `__or__` 
trio)... but I'm sure this is the less common case.

If we're quoting the Zen, then let's not elevate past design patterns to 
"rules". Besides, practicality beats purity. ;)
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/L5ODZ2TEEY2T53C5KB25WJPFGJAU7IIP/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 584: Add Union Operators To dict

2020-02-06 Thread Serhiy Storchaka

06.02.20 21:38, Brandt Bucher пише:

One issue that's come up during PR review with Guido and Serhiy is, when 
evaluating `a | b`, whether or not the default implementation should call an 
overridden `copy()` method on `a` in order to create an instance of the correct 
subclass (rather than a plain-ol' `dict`).


It would create an exception of two rules:

1. Operators on subclasses of builtin classes do not depend on 
overridden methods of arguments (except the corresponding dunder 
method). `list.__add__` and `set.__or__` do not call copy() and 
extend()/update(). You should override the corresponding dunder method 
to change the behavior of the operator.


2. Operators do not depend on non-dunder methods.

This looks to me as a direct violation of the principle "Special cases 
aren't special enough to break the rules."



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 :-)


We can discuss and change the standard handling of subclasses in Python 
builtins. But if it be changed, it should be changed for all builtin 
classes, without exceptions and special cases.


This could resolve a problem with rule 1. But there is still a problem 
with rule 2.

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/4NDSEYFAHZBZOPIYKC4URMFAUGAIE42G/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Clarification of unpacking semantics.

2020-02-06 Thread Guido van Rossum
I like Mark’s new semantics better, but agree with the point about this
being a “feature”.

On Thu, Feb 6, 2020 at 13:06 Paul Moore  wrote:

> On Thu, 6 Feb 2020 at 20:17, Mark Shannon  wrote:
> >
> > I recently unintentionally changed the semantics of this expression
> > `[print("a"), *None, print("b")]`.
> > PEP 448 states that this should raise an exception, but does not specify
> > evaluation order.
> >
> > My implementation was based on the general principle that evaluation in
> > Python is left to right unless specified otherwise.
> >
> > The question is, what should
> >  >>> [print("a"), *None, print("b")]
> >
> > print before raising an exception?
> > I think just "a", Brandt thinks "a" and "b".
> >
> > Brandt argues that I have introduced a bug. I think I have fixed one,
> > admittedly one that I didn't previously realize existed.
>
> I think that if this were a new feature, either order would be
> arguable. But given that this code previously printed "a b", I think
> that changing the order is a change in user-visible behaviour and
> therefore the existing behaviour should be preserved (certainly in
> bugfix releases).
>
> > There is a precedent for fixing evaluation order to be left to right:
> > https://bugs.python.org/issue29652
>
> Changing the order as part of a feature release, listing it as a
> user-visible behaviour change in "What's New" seems acceptable to me.
> But characterising this change as a bug fix doesn't.
>
> > On 06/02/2020 6:28 am, Brandt Bucher wrote:
> > > Commits 13bc139 and 8a4cd70 introduced subtle changes in the
> evaluation logic of unpacking operations. Previously, all elements were
> evaluated prior to being collected in a container. Now, these operations
> are interleaved. For example, the code `[*a, *b]` used to evaluate in the
> order `a` -> `b` -> `a.__iter__()` -> `b.__iter__()`. Now, it evaluates as
> `a` -> `a.__iter__()` -> `b` -> `b.__iter__()`.
> > >
> > > I believe this breaking semantic change is a bug, and I've opened a PR
> to fix it (https://github.com/python/cpython/pull/18264). My reasoning is
> that "unary *" isn't an operator; it doesn't appear on the operator
> precedence table in the docs, and you can't evaluate `*x`. Like the
> brackets and the comma, it's part of the syntax of the outer display
> expression, not the inner one. It specifies how the list should be built,
> so it should be evaluated last, as part of the list construction. And it
> has always been this way since PEP 448 (as far as I can tell).
>
> I agree that it's the *change in behaviour* that's the issue here. We
> should fix that (by reverting to 3.8.1 behaviour) before 3.8.2 gets
> released.
>
> > The lack of explicitly listed precedence for an operator does not mean
> > that it isn't an operator, merely that it doesn't need precedence due to
> > the grammar. For example the slice creation operator `x:y` in `a[x:y]`
> > needs no precedence as it is constrained to only occur in indexing
> > operations. Likewise the unpacking operation `*a` can only occur in
> > certain expressions. That doesn't mean that is not an operation.
>
> I don't think this is a particularly helpful way of looking at it. I
> don't think there's any particular need here to try to argue that
> either behaviour is "right" or "wrong". The previous behaviour has
> been round for some time, and the change in behaviour was (by your own
> admission) inadvertent. Therefore it seems obvious to me that the
> reasonable thing to do is to apply Brandt's PR, that restores the old
> evaluation order (with the *intended* fix from your patch intact, as I
> understand it). If, once this has been done, you still care strongly
> enough to argue for a behaviour change, targeted at 3.9 (assuming
> no-one insists on a deprecation period for the change!), then that's
> fine. Personally I think the arguments either way are weak, and I'd be
> inclined not to care, or to mildly prefer not bothering, in such a
> debate - but let's have the debate once the pressure of "is it OK to
> do this in a bugfix release?" has been removed.
>
> Paul
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/SUIATL7A7M2P3YWYIVIWP5EAM7NRZ5D3/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
-- 
--Guido (mobile)
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/A46XTV6ZHVKSEZYB32SB4M2PNCHIKYSF/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 584: Add Union Operators To dict

2020-02-06 Thread Brandt Bucher
> I see this asymmetry between the | and |= mentioned a few times in the PEP, 
> but I don't see any rationale other than "the authors have decided".

I agree that this probably deserves to be addressed. I can't speak for Steven, 
but I know that my motivation here is to restrict `|` in order to avoid 
confusing casting. It suddenly becomes a very complicated problem with strange 
edge-cases as soon as reflected operations get involved. In contrast, `|=` 
appears in dramatically simpler contexts, so we don't need to worry about 
resolving all of the combinations of possible LHS and RHS types (or whether the 
user can keep up with what we're doing under-the-hood).

I have no idea if this is what motivated the decision in `list`, but I think 
it's a good one.

> The specification mentions "Dict union will return a new dict containing the 
> left operand merged with the right operand, which must be a dict (or an 
> instance of a dict subclass)." Can you clarify if it is part of the spec that 
> it will always return a dict even if one or both of the operands is a dict 
> subclass?

See my recent post on this here. I believe that we should call an overridden 
`lhs.copy()`, but others disagreed during code review. For what it's worth, 
it's probably not good for us to use "dict" and "`dict`" (with 
monospace/backticks) to mean different things in the PEP... ;)

> Unless there is compelling reason to do otherwise, I am in favor of trying to 
> retain subclass identity after operation.

I'll count you as a vote for `new = lhs.copy(); dict.update(new, rhs)`, then. ;)
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/MRYKAFWIJFODH7PBVH5CKPWAS2M26VFO/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Clarification of unpacking semantics.

2020-02-06 Thread Brandt Bucher
> We should fix that (by reverting to 3.8.1 behaviour) before 3.8.2 gets 
> released.

The commits which changed the behavior were bytecode/compiler changes that only 
went to master. I don't think they are present on any other branches.
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/GC3PGIGXFY47RQVOA4HLE3VX5IQ2VGTB/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Clarification of unpacking semantics.

2020-02-06 Thread Paul Moore
On Thu, 6 Feb 2020 at 20:17, Mark Shannon  wrote:
>
> I recently unintentionally changed the semantics of this expression
> `[print("a"), *None, print("b")]`.
> PEP 448 states that this should raise an exception, but does not specify
> evaluation order.
>
> My implementation was based on the general principle that evaluation in
> Python is left to right unless specified otherwise.
>
> The question is, what should
>  >>> [print("a"), *None, print("b")]
>
> print before raising an exception?
> I think just "a", Brandt thinks "a" and "b".
>
> Brandt argues that I have introduced a bug. I think I have fixed one,
> admittedly one that I didn't previously realize existed.

I think that if this were a new feature, either order would be
arguable. But given that this code previously printed "a b", I think
that changing the order is a change in user-visible behaviour and
therefore the existing behaviour should be preserved (certainly in
bugfix releases).

> There is a precedent for fixing evaluation order to be left to right:
> https://bugs.python.org/issue29652

Changing the order as part of a feature release, listing it as a
user-visible behaviour change in "What's New" seems acceptable to me.
But characterising this change as a bug fix doesn't.

> On 06/02/2020 6:28 am, Brandt Bucher wrote:
> > Commits 13bc139 and 8a4cd70 introduced subtle changes in the evaluation 
> > logic of unpacking operations. Previously, all elements were evaluated 
> > prior to being collected in a container. Now, these operations are 
> > interleaved. For example, the code `[*a, *b]` used to evaluate in the order 
> > `a` -> `b` -> `a.__iter__()` -> `b.__iter__()`. Now, it evaluates as `a` -> 
> > `a.__iter__()` -> `b` -> `b.__iter__()`.
> >
> > I believe this breaking semantic change is a bug, and I've opened a PR to 
> > fix it (https://github.com/python/cpython/pull/18264). My reasoning is that 
> > "unary *" isn't an operator; it doesn't appear on the operator precedence 
> > table in the docs, and you can't evaluate `*x`. Like the brackets and the 
> > comma, it's part of the syntax of the outer display expression, not the 
> > inner one. It specifies how the list should be built, so it should be 
> > evaluated last, as part of the list construction. And it has always been 
> > this way since PEP 448 (as far as I can tell).

I agree that it's the *change in behaviour* that's the issue here. We
should fix that (by reverting to 3.8.1 behaviour) before 3.8.2 gets
released.

> The lack of explicitly listed precedence for an operator does not mean
> that it isn't an operator, merely that it doesn't need precedence due to
> the grammar. For example the slice creation operator `x:y` in `a[x:y]`
> needs no precedence as it is constrained to only occur in indexing
> operations. Likewise the unpacking operation `*a` can only occur in
> certain expressions. That doesn't mean that is not an operation.

I don't think this is a particularly helpful way of looking at it. I
don't think there's any particular need here to try to argue that
either behaviour is "right" or "wrong". The previous behaviour has
been round for some time, and the change in behaviour was (by your own
admission) inadvertent. Therefore it seems obvious to me that the
reasonable thing to do is to apply Brandt's PR, that restores the old
evaluation order (with the *intended* fix from your patch intact, as I
understand it). If, once this has been done, you still care strongly
enough to argue for a behaviour change, targeted at 3.9 (assuming
no-one insists on a deprecation period for the change!), then that's
fine. Personally I think the arguments either way are weak, and I'd be
inclined not to care, or to mildly prefer not bothering, in such a
debate - but let's have the debate once the pressure of "is it OK to
do this in a bugfix release?" has been removed.

Paul
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/SUIATL7A7M2P3YWYIVIWP5EAM7NRZ5D3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 584: Add Union Operators To dict

2020-02-06 Thread Paul Ganssle
Hi Brandt, very nice PEP. I have two questions here.

First:

> - The proposal in its current form is very easy to wrap your head around: "|" 
> takes dicts, "|=" takes anything dict.update does.

I see this asymmetry between the | and |= mentioned a few times in the
PEP, but I don't see any rationale other than "the authors have
decided". I am not saying that this is the wrong decision, but the
reasoning behind this choice is not obvious, and I think it might be a
good idea to include the rationale in the PEP. I'd say the asymmetry
between list's `__add__` and `__iadd__` semantics is actually fairly
confusing for anyone who hasn't encountered it before:

>>> a = []
>>> a = a + "one" 
---
TypeError Traceback (most recent
call last)
 in 
> 1 a = a + "one"

TypeError: can only concatenate list (not "str") to list
>>> a += "one"
>>> a
['o', 'n', 'e']

I think most people would be surprised at the difference in semantics
here and this also an example of a situation where it's not obvious that
the "call `list.extend`" behavior is the right thing to do. It would be
nice to see why you rejected:

1. Giving |= `.update` semantics rather than the semantics you chose for |.

2. Giving `|` the same semantics as `|=`.

Second question:

The specification mentions "Dict union will return a new dict containing
the left operand merged with the right operand, which must be a dict (or
an instance of a dict subclass)." Can you clarify if it is part of the
spec that it will always return a `dict` even if one or both of the
operands is a dict subclass? You mentioned in another post that this is
deliberately intended to be subclass-friendly, but if it always returns
`dict`, then I would expect this:

    >>> class MyDict(dict):
    ...    pass
    ...
    >>> MyDict({1: 2}) | MyDict({3: 4})
    {1: 2, 3: 4}

I realize that there's a lot of precedent for this with other builtin
types (int subclasses reverting to int with +, etc), though generally
the justifications for this are two-fold:

1. For symmetrical operations like addition it's not obvious which
operand's type should prevail, particularly if the two are both
different dict subclasses. I think in this case | is already
asymmetrical and it would be relatively natural to think of the right
thing to do as "make a copy of the LHS then update it with the RHS"
(thus retaining the subtype of the LHS).

2. Subclasses may override the constructor in unpredictable ways, so we
don't know how to construct arbitrary subtypes. I /think/ this objection
could be satisfied by using logic equivalent to `copy.copy` for the LHS
when it is a dict subclass, and then using the mapping protocol on the RHS.

Unless there is compelling reason to do otherwise, I am in favor of
trying to retain subclass identity after operations, but either way it
would be good to be explicit about it in the specification and maybe
include a bit of the rationale one way or the other.

Best,
Paul



signature.asc
Description: OpenPGP digital signature
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/L44V6WTFI4OWM7TPYIMCACJHKBRJQMIU/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Clarification of unpacking semantics.

2020-02-06 Thread Mark Shannon

Hi everyone,

I recently unintentionally changed the semantics of this expression
`[print("a"), *None, print("b")]`.
PEP 448 states that this should raise an exception, but does not specify 
evaluation order.


My implementation was based on the general principle that evaluation in 
Python is left to right unless specified otherwise.


The question is, what should
>>> [print("a"), *None, print("b")]

print before raising an exception?
I think just "a", Brandt thinks "a" and "b".

Brandt argues that I have introduced a bug. I think I have fixed one, 
admittedly one that I didn't previously realize existed.


There is a precedent for fixing evaluation order to be left to right:
https://bugs.python.org/issue29652

On 06/02/2020 6:28 am, Brandt Bucher wrote:

Commits 13bc139 and 8a4cd70 introduced subtle changes in the evaluation logic of unpacking 
operations. Previously, all elements were evaluated prior to being collected in a container. Now, 
these operations are interleaved. For example, the code `[*a, *b]` used to evaluate in the order 
`a` -> `b` -> `a.__iter__()` -> `b.__iter__()`. Now, it evaluates as `a` -> 
`a.__iter__()` -> `b` -> `b.__iter__()`.

I believe this breaking semantic change is a bug, and I've opened a PR to fix it 
(https://github.com/python/cpython/pull/18264). My reasoning is that "unary *" 
isn't an operator; it doesn't appear on the operator precedence table in the docs, and 
you can't evaluate `*x`. Like the brackets and the comma, it's part of the syntax of the 
outer display expression, not the inner one. It specifies how the list should be built, 
so it should be evaluated last, as part of the list construction. And it has always been 
this way since PEP 448 (as far as I can tell).
The lack of explicitly listed precedence for an operator does not mean 
that it isn't an operator, merely that it doesn't need precedence due to 
the grammar. For example the slice creation operator `x:y` in `a[x:y]` 
needs no precedence as it is constrained to only occur in indexing 
operations. Likewise the unpacking operation `*a` can only occur in 
certain expressions. That doesn't mean that is not an operation.




The docs themselves seem to support this line of reasoning 
(https://docs.python.org/3/reference/expressions.html#evaluation-order):


In the following lines, expressions will be evaluated in the arithmetic order 
of their suffixes:
...
expr1(expr2, expr3, *expr4, **expr5)


Note that the stars are not part of expressions 1-5, but are a part of the 
top-level call expression that operates on them all.


There are many layers of grammar that make up a call. It is entirely 
arbitrary what you call an expression or some other grammatical entity.

`*expr4` is parsed as an argument, the same as `expr2`.

Cheers,
Mark.



Mark Shannon disagrees with me (I'll let him reply rather than attempt to 
summarize his argument for him), but we figured it might be better to get more 
input here on exactly whether you all think the behavior should change or not. 
You can see the discussion on the PR itself for some additional points and 
context.

Thanks!

Brandt
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/4HS2ZEQWWFMQ7IO5ZHBNWEYLN4PIYDCD/
Code of Conduct: http://python.org/psf/codeofconduct/


___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/VUSNP43ALB6YS2TINDTON6F5Y56EG7HV/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Clarification of unpacking semantics.

2020-02-06 Thread Terry Reedy

On 2/6/2020 2:26 PM, Mark Shannon wrote:

In the python grammar, an 'expression' is a 'starred_item' but a 
'starred_item' need not be an expression.


starred_item ::=  expression | "*" or_expr
expression ::=  conditional_expression | lambda_expr
conditional_expression ::=  or_test ["if" or_test "else" expression]

'*a' is a 'starred_item' but not an 'expression'.


I don't know where you got that grammar from, but not GitHub
https://github.com/python/cpython/blob/master/Grammar/Grammar#L142


From the human readable docs

https://docs.python.org/3/reference/expressions.html#expression-lists

https://docs.python.org/3/reference/expressions.html#conditional-expressions

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/YYVDKK2FODTHFXN26LEUE2DJTOXGYWXB/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 584: Add Union Operators To dict

2020-02-06 Thread Brandt Bucher
One issue that's come up during PR review with Guido and Serhiy is, when 
evaluating `a | b`, whether or not the default implementation should call an 
overridden `copy()` method on `a` in order to create an instance of the correct 
subclass (rather than a plain-ol' `dict`). For example, `defaultdict` works 
correctly without any additional modification:

```
>>> from collections import defaultdict
>>> i = defaultdict(int, {1: 1, 2: 2})
>>> s = defaultdict(str, {2: "2", 3: "3"})
>>> i | s
defaultdict(, {1: 1, 2: '2', 3: '3'})
>>> s | i
defaultdict(, {2: 2, 3: '3', 1: 1})
```

So this has immediate benefits for both usability and maintenance: subclasses 
only need to override `copy()` to get working `__or__`/`__ror__` behavior. 
While this isn't what `list` and `set` do, for example, I argue that `dict` is 
more often subclassed, and we shouldn't blindly follow the precedent of their 
behavior when designing a new API for `dict`.

We decided to bring the discussion here to get input from a larger audience. 
I'm currently +0 on calling `copy()`, but I know Steven feels a bit more 
strongly about this than I do:

> 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 :-)

The more detailed thread of discussion starts at 
https://github.com/python/cpython/pull/12088#issuecomment-582609024 (note that 
we are no longer considering calling an overridden `update` method).
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/Z5SSGCH736UWHKFGJEZROH6VKPKXIT7W/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Clarification of unpacking semantics.

2020-02-06 Thread Mark Shannon



On 06/02/2020 6:30 pm, Terry Reedy wrote:

On 2/6/2020 1:28 AM, Brandt Bucher wrote:
Commits 13bc139 and 8a4cd70 introduced subtle changes in the 
evaluation logic of unpacking operations. Previously, all elements 
were evaluated prior to being collected in a container. Now, these 
operations are interleaved. For example, the code `[*a, *b]` used to 
evaluate in the order `a` -> `b` -> `a.__iter__()` -> `b.__iter__()`. 
Now, it evaluates as `a` -> `a.__iter__()` -> `b` -> `b.__iter__()`.


A simpler example, which sharpens the contrast, is [*a, b].  The 
unpacking of *b is last either way. The change is from eval(a), eval(b), 
extend(a.__iter__()), append b

to   eval(a), extend(a.__iter__()), eval(b), append b

I believe this breaking semantic change is a bug, and I've opened a PR 
to fix it (https://github.com/python/cpython/pull/18264).


I carefully read and considered the original issue and the discussion on 
the PR and agree with the intent of the PR.


The semantic change can have visible effects due to interaction of 
side-effects.  Examples on the PR are

1. a.__iter__ raising while b prints
    ([*None, print('executed)]), and
2. a and b both involving the same iterator
    (*it, next(it))

These previously unannounced semantic changes are apparently gratuitous 
side-effects of an internal refactoring.  They should only be made, if 
at all, after discussion and agreement, then announcement and a 
deprecation period.  But I seen no reason to change the status quo 
semantics.


These changes were unannounced because I didn't realize the current 
implementation was broken. There were no tests for raising an exception 
in the middle of unpacking a list, and it didn't occur to me to add them.




My reasoning is that "unary *" isn't an operator; it doesn't appear on 
the operator precedence table in the docs, and you can't evaluate 
`*x`. Like the brackets and the comma, it's part of the syntax of the 
outer display expression, not the inner one. It specifies how the list 
should be built, so it should be evaluated last, as part of the list 
construction. And it has always been this way since PEP 448 (as far as 
I can tell).


I agree that '*a' is not an expression in the meaning relevant here. 
https://docs.python.org/3/glossary.html
says "A piece of syntax which can be evaluated to some value."  This is 
the common math/logic/CS meaning.  '*a' cannot be evaluated to a Python 
object.  It is not an 'expression statement and cannot be passed to eval().


In the python grammar, an 'expression' is a 'starred_item' but a 
'starred_item' need not be an expression.


starred_item ::=  expression | "*" or_expr
expression ::=  conditional_expression | lambda_expr
conditional_expression ::=  or_test ["if" or_test "else" expression]

'*a' is a 'starred_item' but not an 'expression'.


I don't know where you got that grammar from, but not GitHub
https://github.com/python/cpython/blob/master/Grammar/Grammar#L142




The docs themselves seem to support this line of reasoning 
(https://docs.python.org/3/reference/expressions.html#evaluation-order):


In the following lines, expressions will be evaluated in the 
arithmetic order of their suffixes:

...
expr1(expr2, expr3, *expr4, **expr5)


Note that the stars are not part of expressions 1-5, but are a part of 
the top-level call expression that operates on them all.


Mark Shannon disagrees with me (I'll let him reply rather than attempt 
to summarize his argument for him), but we figured it might be better 
to get more input here on exactly whether you all think the behavior 
should change or not. You can see the discussion on the PR itself for 
some additional points and context.



___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/THKSHB2PSZBJPHMM5AACFLDJRCV6I24P/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Clarification of unpacking semantics.

2020-02-06 Thread Terry Reedy

On 2/6/2020 1:28 AM, Brandt Bucher wrote:

Commits 13bc139 and 8a4cd70 introduced subtle changes in the evaluation logic of unpacking 
operations. Previously, all elements were evaluated prior to being collected in a container. Now, 
these operations are interleaved. For example, the code `[*a, *b]` used to evaluate in the order 
`a` -> `b` -> `a.__iter__()` -> `b.__iter__()`. Now, it evaluates as `a` -> 
`a.__iter__()` -> `b` -> `b.__iter__()`.


A simpler example, which sharpens the contrast, is [*a, b].  The 
unpacking of *b is last either way. The change is from eval(a), eval(b), 
extend(a.__iter__()), append b

to   eval(a), extend(a.__iter__()), eval(b), append b


I believe this breaking semantic change is a bug, and I've opened a PR to fix 
it (https://github.com/python/cpython/pull/18264).


I carefully read and considered the original issue and the discussion on 
the PR and agree with the intent of the PR.


The semantic change can have visible effects due to interaction of 
side-effects.  Examples on the PR are

1. a.__iter__ raising while b prints
   ([*None, print('executed)]), and
2. a and b both involving the same iterator
   (*it, next(it))

These previously unannounced semantic changes are apparently gratuitous 
side-effects of an internal refactoring.  They should only be made, if 
at all, after discussion and agreement, then announcement and a 
deprecation period.  But I seen no reason to change the status quo 
semantics.



My reasoning is that "unary *" isn't an operator; it doesn't appear on the 
operator precedence table in the docs, and you can't evaluate `*x`. Like the brackets and 
the comma, it's part of the syntax of the outer display expression, not the inner one. It 
specifies how the list should be built, so it should be evaluated last, as part of the 
list construction. And it has always been this way since PEP 448 (as far as I can tell).


I agree that '*a' is not an expression in the meaning relevant here. 
https://docs.python.org/3/glossary.html
says "A piece of syntax which can be evaluated to some value."  This is 
the common math/logic/CS meaning.  '*a' cannot be evaluated to a Python 
object.  It is not an 'expression statement and cannot be passed to eval().


In the python grammar, an 'expression' is a 'starred_item' but a 
'starred_item' need not be an expression.


starred_item ::=  expression | "*" or_expr
expression ::=  conditional_expression | lambda_expr
conditional_expression ::=  or_test ["if" or_test "else" expression]

'*a' is a 'starred_item' but not an 'expression'.


The docs themselves seem to support this line of reasoning 
(https://docs.python.org/3/reference/expressions.html#evaluation-order):


In the following lines, expressions will be evaluated in the arithmetic order 
of their suffixes:
...
expr1(expr2, expr3, *expr4, **expr5)


Note that the stars are not part of expressions 1-5, but are a part of the 
top-level call expression that operates on them all.

Mark Shannon disagrees with me (I'll let him reply rather than attempt to 
summarize his argument for him), but we figured it might be better to get more 
input here on exactly whether you all think the behavior should change or not. 
You can see the discussion on the PR itself for some additional points and 
context.


--
Terry Jan Reedy
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/R74GKY6HL5SB5O4GBWPYYMINQAVLXXQH/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 584: Add Union Operators To dict

2020-02-06 Thread Chris Angelico
On Thu, Feb 6, 2020 at 7:42 PM Musbur  wrote:
>
> Depends on what d is.
>
> >>> type({})
> 
>
> So the result is  {(1, 2): None}, but the ambiguity comes from the
> definition of {}, not from my proposal.
>

Actually, what Serhiy hinted at was a consequence (and, I would say, a
rather weird corner case) of the current definition of |= as being
"equivalent to update()". Since update() will accept a number of
things, including an iterable of pairs, it's actually possible to use
a set of two-element tuples as a representation of keys and values. It
seems pretty unlikely that anyone would use a *set* for this (as
opposed to, say, a list or generator), but it does mean that your
proposal would conflict with that. Which in turn means you're actually
asking for |= to special-case sets; not impossible, by any means, but
it's a definite change and not simply a logical extension of current
behaviour.

I don't think supporting sets in |= is worth this confusion,
especially since there's no easy way to override the choice of value.
It'd be just as easy to do thing|=dict.fromkeys(s) and avoid the whole
issue. However, IMO the &= operator would be better able to accept a
set, and this is something that wouldn't conflict (and thus can be
safely added later).

ChrisA
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/BTYIZSBWR3O5JRIGFHOZWVIPUISUGDHB/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 584: Add Union Operators To dict

2020-02-06 Thread Musbur

Depends on what d is.


type({})



So the result is  {(1, 2): None}, but the ambiguity comes from the 
definition of {}, not from my proposal.



Am 05.02.2020 18:19 schrieb Serhiy Storchaka:

05.02.20 14:27, Musbur пише:
I have one suggestion: Wouldn't it be useful for these operators to 
also accept sets (functionally acting like a dict with None for all 
values)? This would make it very elegant to 'normalize' dicts by 
pruning (dict & set) or padding (set | dict) dictionaries. I would 
find this useful for efficient data sanitation purposes, as when 
processing input from web forms.


   d = {}
   d |= {(1, 2)}

What is d now? {1: 2} or {(1, 2): None}
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at
https://mail.python.org/archives/list/python-dev@python.org/message/ZUXJBYUHXGAKLH3TOVB4UUXQUBFOQAIK/
Code of Conduct: http://python.org/psf/codeofconduct/

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/2ENA4EV2IVHTE64YVXT4MK52MYU5PLGR/
Code of Conduct: http://python.org/psf/codeofconduct/