Re: [Python-ideas] [Python-Dev] What's the status of PEP 505: None-aware operators?
On Tue, Nov 28, 2017 at 12:31:06PM -0800, Raymond Hettinger wrote:
I also cc python-dev to see if anybody here is strongly in favor or against this inclusion.
Put me down for a strong -1. The proposal would occasionally save a few keystokes but comes at the expense of giving Python a more Perlish look and a more arcane feel.
I think that's an unfair characterisation of the benefits of the PEP. It's not just "a few keystrokes". Ironically, the equivalent in Perl is // which Python has used for truncating division since version 2.4 or so. So if we're in danger of looking "Perlish", that ship has sailed a long time ago. Perl is hardly the only language with null-coalescing operators -- we might better describe ?? as being familiar to C#, PHP, Swift and Dart. That's two mature, well-known languages and two up-and-coming languages. [...]
timeout ?? local_timeout ?? global_timeout
As opposed to the status quo: timeout if timeout is not None else (local_timeout if local_timeout is not None else global_timeout) Or shorter, but even harder to understand: (global_timeout if local_timeout is None else local_timeout) if timeout is None else timeout I'd much prefer to teach the version with ?? -- it has a simple explanation: "the first of the three given values which isn't None". The ?? itself needs to be memorized, but that's no different from any other operator. The first time I saw ** I was perplexed and couldn't imagine what it meaned. Here ?? doesn't merely save a few keystrokes, it significantly reduces the length and complexity of the expression and entirely cuts out the duplication of names. If you can teach timeout or local_timeout or global_timeout then you ought to be able to teach ??, as it is simpler: it only compares to None, and avoids needing to explain or justify Python's truthiness model.
'foo' in (None ?? ['foo', 'bar'])
If you can understand 'foo' in (False or ['foo', 'bar']) then surely you can understand the version with ??.
requested_quantity ?? default_quantity * price
Again: (default_quantity if requested_quantity is None else requested_quantity) * price I'd much prefer to read, write and teach the version with ?? over the status quo. -- Steve
Strong -1 still from me. Too special case for syntax. Just write a function 'first_non_none()' that can perfectly will handle the need. On Nov 28, 2017 10:09 PM, "Steven D'Aprano" <steve@pearwood.info> wrote:
On Tue, Nov 28, 2017 at 12:31:06PM -0800, Raymond Hettinger wrote:
I also cc python-dev to see if anybody here is strongly in favor or
against this inclusion.
Put me down for a strong -1. The proposal would occasionally save a few keystokes but comes at the expense of giving Python a more Perlish look and a more arcane feel.
I think that's an unfair characterisation of the benefits of the PEP. It's not just "a few keystrokes".
Ironically, the equivalent in Perl is // which Python has used for truncating division since version 2.4 or so. So if we're in danger of looking "Perlish", that ship has sailed a long time ago.
Perl is hardly the only language with null-coalescing operators -- we might better describe ?? as being familiar to C#, PHP, Swift and Dart. That's two mature, well-known languages and two up-and-coming languages.
[...]
timeout ?? local_timeout ?? global_timeout
As opposed to the status quo:
timeout if timeout is not None else (local_timeout if local_timeout is not None else global_timeout)
Or shorter, but even harder to understand:
(global_timeout if local_timeout is None else local_timeout) if timeout is None else timeout
I'd much prefer to teach the version with ?? -- it has a simple explanation: "the first of the three given values which isn't None". The ?? itself needs to be memorized, but that's no different from any other operator. The first time I saw ** I was perplexed and couldn't imagine what it meaned.
Here ?? doesn't merely save a few keystrokes, it significantly reduces the length and complexity of the expression and entirely cuts out the duplication of names.
If you can teach
timeout or local_timeout or global_timeout
then you ought to be able to teach ??, as it is simpler: it only compares to None, and avoids needing to explain or justify Python's truthiness model.
'foo' in (None ?? ['foo', 'bar'])
If you can understand
'foo' in (False or ['foo', 'bar'])
then surely you can understand the version with ??.
requested_quantity ?? default_quantity * price
Again:
(default_quantity if requested_quantity is None else requested_quantity) * price
I'd much prefer to read, write and teach the version with ?? over the status quo.
-- Steve _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
On 29 November 2017 at 16:13, David Mertz <mertz@gnosis.cx> wrote:
Strong -1 still from me. Too special case for syntax. Just write a function 'first_non_none()' that can perfectly will handle the need.
That's the equivalent of SQL's COALESCE, and it's insufficient for the same reason "and" and "or" are syntax rather than builtins: the function form doesn't provide short-circuiting behaviour. As far as utility goes, I put it in a similar category to matrix multiplication: if you don't need it, you don't need it, but when you do need it, you need it a *lot*. The use case where these operations come up is when you're working with partially structured hierarchical data (*cough*JSON*cough*). In those kinds of structures, None is frequently used as a marker to say "this entire subtree is missing", and you either want to propagate that None, or else replace it with something else (and the "something else" may be a network call to a different service, so you definitely don't want to do it if you don't need to). So I'd remind folks to try to avoid the "I don't need this, so nobody needs this" mistake. It's OK to say "the use case exists, but I still don't want that particular syntax for it in Python" (I'm personally inclined to agree with you on that front). It's not OK to try to claim there are no use cases where the status quo is awkward enough to become irritating (since it's an empirically false statement that you don't need to be making). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
2017-11-29 11:14 GMT+03:00 Nick Coghlan <ncoghlan@gmail.com>:
It's OK to say "the use case exists, but I still don't want that particular syntax for it in Python" (I'm personally inclined to agree with you on that front). It's not OK to try to claim there are no use cases where the status quo is awkward enough to become irritating (since it's an empirically false statement that you don't need to be making).
If the problem with the proposed syntax, but there are cases for use, it may be worth to bikeshed one more time? 2017-11-29 9:08 GMT+03:00 Steven D'Aprano <steve@pearwood.info>: I'd much prefer to read, write and teach the version with ?? over the
status quo.
Since the proposed semantics is more similar to the idea of "or", may be it is better to consider something like: timeout then local_timeout then global_timeout I do not know how much this is a frequent case to be worthy of a keyword. With kind regards, -gdg 2017-11-29 11:14 GMT+03:00 Nick Coghlan <ncoghlan@gmail.com>:
On 29 November 2017 at 16:13, David Mertz <mertz@gnosis.cx> wrote:
Strong -1 still from me. Too special case for syntax. Just write a function 'first_non_none()' that can perfectly will handle the need.
That's the equivalent of SQL's COALESCE, and it's insufficient for the same reason "and" and "or" are syntax rather than builtins: the function form doesn't provide short-circuiting behaviour.
As far as utility goes, I put it in a similar category to matrix multiplication: if you don't need it, you don't need it, but when you do need it, you need it a *lot*.
The use case where these operations come up is when you're working with partially structured hierarchical data (*cough*JSON*cough*). In those kinds of structures, None is frequently used as a marker to say "this entire subtree is missing", and you either want to propagate that None, or else replace it with something else (and the "something else" may be a network call to a different service, so you definitely don't want to do it if you don't need to).
So I'd remind folks to try to avoid the "I don't need this, so nobody needs this" mistake. It's OK to say "the use case exists, but I still don't want that particular syntax for it in Python" (I'm personally inclined to agree with you on that front). It's not OK to try to claim there are no use cases where the status quo is awkward enough to become irritating (since it's an empirically false statement that you don't need to be making).
Cheers, Nick.
-- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
On 29 November 2017 at 18:49, Kirill Balunov <kirillbalunov@gmail.com> wrote:
2017-11-29 11:14 GMT+03:00 Nick Coghlan <ncoghlan@gmail.com>:
It's OK to say "the use case exists, but I still don't want that particular syntax for it in Python" (I'm personally inclined to agree with you on that front). It's not OK to try to claim there are no use cases where the status quo is awkward enough to become irritating (since it's an empirically false statement that you don't need to be making).
If the problem with the proposed syntax, but there are cases for use, it may be worth to bikeshed one more time?
I don't think enough time has passed since we first discussed it. Since Guido has already said "not for 3.7", we can give folks another 12+ months to ponder the problem, and then maybe revisit it for 3.8. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
Kirill Balunov <kirillbalunov@gmail.com> writes:
Since the proposed semantics is more similar to the idea of "or", may be it is better to consider something like:
timeout then local_timeout then global_timeout
I do not know how much this is a frequent case to be worthy of a keyword.
That sounds awkward... what about timeout else local_timeout else global_timeout instead? ciao, lele. -- nickname: Lele Gaifax | Quando vivrò di quello che ho pensato ieri real: Emanuele Gaifas | comincerò ad aver paura di chi mi copia. lele@metapensiero.it | -- Fortunato Depero, 1929.
בתאריך יום ד׳, 29 בנוב׳ 2017, 12:29, מאת Lele Gaifax <lele@metapensiero.it
:
Kirill Balunov <kirillbalunov@gmail.com> writes:
Since the proposed semantics is more similar to the idea of "or", may be it is better to consider something like:
timeout then local_timeout then global_timeout
I do not know how much this is a frequent case to be worthy of a keyword.
That sounds awkward... what about
timeout else local_timeout else global_timeout
instead?
I think then and else can be ruled out since they can be very confusing when used in a conditinal statement or a comprehension. x = a if x else y else b # wait. what? Elazar
I didn't say no use case exists, but rather "too special case." And/or shortcutting is great, but truthiness feels much more general than noneness to me. But yes, 'first_non_none()" might have to address laziness in some manner, depending on the use case. Zero argument lambdas and expression quoting are the usual hacks (yes, both ugly in their own ways). On Nov 29, 2017 12:14 AM, "Nick Coghlan" <ncoghlan@gmail.com> wrote: On 29 November 2017 at 16:13, David Mertz <mertz@gnosis.cx> wrote:
Strong -1 still from me. Too special case for syntax. Just write a function 'first_non_none()' that can perfectly will handle the need.
That's the equivalent of SQL's COALESCE, and it's insufficient for the same reason "and" and "or" are syntax rather than builtins: the function form doesn't provide short-circuiting behaviour. As far as utility goes, I put it in a similar category to matrix multiplication: if you don't need it, you don't need it, but when you do need it, you need it a *lot*. The use case where these operations come up is when you're working with partially structured hierarchical data (*cough*JSON*cough*). In those kinds of structures, None is frequently used as a marker to say "this entire subtree is missing", and you either want to propagate that None, or else replace it with something else (and the "something else" may be a network call to a different service, so you definitely don't want to do it if you don't need to). So I'd remind folks to try to avoid the "I don't need this, so nobody needs this" mistake. It's OK to say "the use case exists, but I still don't want that particular syntax for it in Python" (I'm personally inclined to agree with you on that front). It's not OK to try to claim there are no use cases where the status quo is awkward enough to become irritating (since it's an empirically false statement that you don't need to be making). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On Wed, Nov 29, 2017 at 06:49:14AM -0800, David Mertz wrote:
I didn't say no use case exists, but rather "too special case." And/or shortcutting is great, but truthiness feels much more general than noneness to me.
Of course truthiness is much more general than Noneness -- and that's precisely the problem with using `or`. It's too general. If you haven't read the PEP, you should, because this is extensively discussed there. One of the problems the author discusses is that `or` is recommended on Stackoverflow as the best way to perform short-cutting None tests, often with no caveats given. We've been here before. Python old-timers may remember the former idiomatic way to get a ternary if expression: condition and first or second which was also buggy (if first happens to be falsey, second is returned even when condition is true). -- Steve
On Wed, 29 Nov 2017 18:14:36 +1000 Nick Coghlan <ncoghlan@gmail.com> wrote:
As far as utility goes, I put it in a similar category to matrix multiplication: if you don't need it, you don't need it, but when you do need it, you need it a *lot*.
As someone who appreciates both the matrix multiplication operator and "async/await", I really don't think PEP 505-style operators (regardless of their spellings) fall into the same conceptual bucket. There's no risk of matrix multiplication operators bleeding into non-domain specific code, and the readers of domain specific code already know about the matrix multiplication operator and what it does (or they should anyway, since it's so damn useful). It's like "async/await": you won't find them in regular non-async code, so the mental burden only falls on specialists who write and read event-driven networking code (mostly, even though Guido would like to see parsers based on the idiom too :-)). Conversely, PEP 505-style operators may appear in everyday code regardless of their application domain or target. This in turn increases the mental burden for *everyone*. Regards Antoine.
On 1 December 2017 at 04:49, Antoine Pitrou <solipsis@pitrou.net> wrote:
On Wed, 29 Nov 2017 18:14:36 +1000 Nick Coghlan <ncoghlan@gmail.com> wrote:
As far as utility goes, I put it in a similar category to matrix multiplication: if you don't need it, you don't need it, but when you do need it, you need it a *lot*.
As someone who appreciates both the matrix multiplication operator and "async/await", I really don't think PEP 505-style operators (regardless of their spellings) fall into the same conceptual bucket.
There's no risk of matrix multiplication operators bleeding into non-domain specific code, and the readers of domain specific code already know about the matrix multiplication operator and what it does (or they should anyway, since it's so damn useful). It's like "async/await": you won't find them in regular non-async code, so the mental burden only falls on specialists who write and read event-driven networking code (mostly, even though Guido would like to see parsers based on the idiom too :-)). Conversely, PEP 505-style operators may appear in everyday code regardless of their application domain or target. This in turn increases the mental burden for *everyone*.
I genuinely don't think these kinds of operators are all that useful outside the specific domain of working with semi-structured hierarchical data stored in graph databases and document stores like MongoDB, ElasticSearch, and PostgreSQL JSONB columns, or else piping data between such stores and JSON consuming clients. If there was a high change of their being broadly adopted outside those domains, I don't think we'd be seeing the sharp division of opinion that we see between folks that consider these operators to be obviously useful, and those that are honestly befuddled as to why on earth anyone would ever want them. It's just that where matrix multiplication and async programming have rich vocabularies and computer science foundations to draw on, the None-aware and None-severing operators in different languages arise more from the pragmatic hackery of working with semi-structured data for tasks that are essentially a matter of reshaping blobs of JSON from one system to feed into another (it's an imperative approach to the kind of work that XSLT does for XML in a more declarative way). The closest mathematical equivalent is a quiet NaN, but the PEP already discusses some of the limitations of pursuing that approach for algorithmic operations in Python: https://www.python.org/dev/peps/pep-0505/#haskell-style-maybe I think the PEP as currently written honestly goes too far into symbolic magic, and hence doesn't give a reader enough hints to plausibly guess what "?." means if they've never seen it before: return jsonify( first_seen=site.first_seen?.isoformat(), id=site.id, is_active=site.is_active, last_seen=site.last_seen?.isoformat(), url=site.url.rstrip('/') ) Thus the idea of possibly using "??" as a pronoun symbol (akin to "_" at the interactive prompt) to allow both the condition and the RHS in a conditional expression to refer to the LHS: return jsonify( first_seen = site.first_seen if ?? is None else ??.isoformat(), id=site.id, is_active = site.is_active, last_seen = site.last_seen if ?? is None else ??.isoformat(), url = site.url.rstrip('/') ) Here, even someone who's never seen "??" before has at least some chance of guessing "OK, it looks like some kind of implicitly defined variable reference. What might it be referring to? Well, the code calls a method on it if it isn't None, so perhaps it means the LHS of the conditional expression it appears in?". And the transcription to English would probably use an actual pronoun: "We set first_seen to site.first_seen if that's None, otherwise we set it to the result of site.first_seen's isoformat() method" Further suggesting a potential name for the symbol: a "that" reference. (Where precisely what "that" refers to will depend on where the symbol appears, similar to regular pronoun usage in English). It isn't the same way that languages that use "<cond> ? <then> : <else>" for their conditional expression syntax do things, but spelling conditional expressions as "<then> if <cond> else <else>" is already pretty unique in its own right :) "That" references could also be expanded to comprehensions and generator expressions in a fairly useful way: [f(x) for x in iterable if ?? is not None] Pronounced something like "f of x, if that's not None, for x in iterable". Cheers, Nick. P.S. As previously noted, I don't think we should rush into anything for 3.7 on this point, hence my deferral of all the related PEPs, rather than requesting pronouncement. I do think the symbolic pronoun idea is potentially worth exploring further for 3.8 though. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On 1 December 2017 at 13:40, Nick Coghlan <ncoghlan@gmail.com> wrote:
I genuinely don't think these kinds of operators are all that useful outside the specific domain of working with semi-structured hierarchical data stored in graph databases and document stores like MongoDB, ElasticSearch, and PostgreSQL JSONB columns, or else piping data between such stores and JSON consuming clients.
In that case, surely there are 3rd party libraries that help with extracting such data from raw objects? Or if not, how seriously has anyone looked at developing one? With the ability to create specialised getattr and getitem behaviour, is it really so difficult to produce a class that allows users to extract hierarchical data? I know it probably couldn't do as good a job as if there were dedicated syntax, but as a basis for a proposal that said "current best practice (using module XXX) looks like this, but would be improved with the following language support" it would help to ground the discussion in real use cases. In the context of comparisons with matrix multiplication, PEP 465 put a lot of time into explaining how all the ways of approaching the problem short of a language change had been tried and found wanting. Maybe PEP 505 should be held to a similar standard? At the moment, 99% of the discussion seems rooted in generalised "it would help a lot of code" with readability arguments based on artificial examples, and that's not really helping move the discussion forward. To be clear, I understand the problem of reading semi-structured data. I've hit it myself and been frustrated by it. But my reaction was "why am I not able to find a library that does this?", and when I couldn't find such a library, my assumption was that people in general don't find the current behaviour sufficiently frustrating to do anything about it. And I was in the same situation - it annoys me, but not enough to write a helper module (and certainly not enough that I'm crying out for a language change). So I do appreciate the need, I just don't think "language change" should be the first thing that's suggested. Paul PS Some of the above may have been covered in the PEPs and previous discussions. I haven't reread them - but any serious reboot of the discussion should probably start with a summary of where we're up to.
On Fri, Dec 1, 2017 at 6:16 AM, Paul Moore <p.f.moore@gmail.com> wrote:
I genuinely don't think these kinds of operators are all that useful outside the specific domain of working with semi-structured hierarchical data stored in graph databases and document stores like MongoDB, ElasticSearch, and PostgreSQL JSONB columns, or else piping data between such stores and JSON consuming clients.
In that case, surely there are 3rd party libraries that help with extracting such data from raw objects?
Sure -- it's handled by validation libraries like Colander, for instance: https://docs.pylonsproject.org/projects/colander/en/latest/ And I'd be shocked if there weren't similar functionality built in to PyMongo and such. Which makes a lot of sense -- if you want to enforce any kind of schema, you need to specify which fields are optional, and handle those cases. So this is perhaps largely about making it easier to write such libraries. Though the other really common use case is None default parameters: def fun(self, par1, par2, par3=None): if par3 is None: self.par3 = something_mutable is a really common idiom -- though not all the verbose. -CHB -- Christopher Barker, Ph.D. Oceanographer Emergency Response Division NOAA/NOS/OR&R (206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception Chris.Barker@noaa.gov
On 2 December 2017 at 00:16, Paul Moore <p.f.moore@gmail.com> wrote:
At the moment, 99% of the discussion seems rooted in generalised "it would help a lot of code" with readability arguments based on artificial examples, and that's not really helping move the discussion forward.
PEP 505 covers this in https://www.python.org/dev/peps/pep-0505/#motivating-examples (with an actual survey of standard library code, as well as some specific motivating examples from real world open source projects).
To be clear, I understand the problem of reading semi-structured data. I've hit it myself and been frustrated by it. But my reaction was "why am I not able to find a library that does this?", and when I couldn't find such a library, my assumption was that people in general don't find the current behaviour sufficiently frustrating to do anything about it. And I was in the same situation - it annoys me, but not enough to write a helper module (and certainly not enough that I'm crying out for a language change). So I do appreciate the need, I just don't think "language change" should be the first thing that's suggested.
The problem is that libraries don't have any way to manipulate attribute access chains in a usefully relevant way - you either have to put the control flow logic in line, or start writing helper functions like: def maybe_traverse_particular_subtree(obj): if obj is None: return None return obj.particular.subtree.of.interest And there are lots of other tricks used to make such code reasonably readable, with one of the most common being "Use a short placeholder variable name", so you get code like: fs = site.first_seen first_seen = fs if fs is None else fs.isodate() (from one of the proposed refactorings of the SiteView example in the PEP) Another variant on the "?? as pronoun" idea would be to use it as a new syntax for defining single argument lambda expressions: def call_if_not_none(lhs, deferred_rhs): return lhs if lhs is not None else deferred_rhs(lhs) first_seen = call_if_not_none(site.first_seen, (??.isodate()) However, I think that would actually be less clear and more confusing than the inline implicit pronoun idea. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
29.11.17 08:08, Steven D'Aprano пише:
Perl is hardly the only language with null-coalescing operators -- we might better describe ?? as being familiar to C#, PHP, Swift and Dart. That's two mature, well-known languages and two up-and-coming languages.
What is the syntax of the ternary operator in these languages?
On Wed, Nov 29, 2017 at 09:14:12AM +0200, Serhiy Storchaka wrote:
29.11.17 08:08, Steven D'Aprano пише:
Perl is hardly the only language with null-coalescing operators -- we might better describe ?? as being familiar to C#, PHP, Swift and Dart. That's two mature, well-known languages and two up-and-coming languages.
What is the syntax of the ternary operator in these languages?
All four use: condition ? first : second for the ternary if operator. -- Steve
בתאריך יום ד׳, 29 בנוב׳ 2017, 11:46, מאת Steven D'Aprano < steve@pearwood.info>:
On Wed, Nov 29, 2017 at 09:14:12AM +0200, Serhiy Storchaka wrote:
29.11.17 08:08, Steven D'Aprano пише:
Perl is hardly the only language with null-coalescing operators -- we might better describe ?? as being familiar to C#, PHP, Swift and Dart. That's two mature, well-known languages and two up-and-coming languages.
What is the syntax of the ternary operator in these languages?
All four use:
condition ? first : second
for the ternary if operator.
This suggests something like "ifNone" keyword : x = a ifNone b ifNone c Elazar
29.11.17 11:45, Steven D'Aprano пише:
On Wed, Nov 29, 2017 at 09:14:12AM +0200, Serhiy Storchaka wrote:
29.11.17 08:08, Steven D'Aprano пише:
Perl is hardly the only language with null-coalescing operators -- we might better describe ?? as being familiar to C#, PHP, Swift and Dart. That's two mature, well-known languages and two up-and-coming languages.
What is the syntax of the ternary operator in these languages?
All four use:
condition ? first : second
for the ternary if operator.
If all four use ?, it is natural that in operators which are shortcuts of the ternary operator they use ?. But in Python the bar of introducing ? is higher.
On 29 November 2017 at 21:53, Serhiy Storchaka <storchaka@gmail.com> wrote:
29.11.17 11:45, Steven D'Aprano пише:
On Wed, Nov 29, 2017 at 09:14:12AM +0200, Serhiy Storchaka wrote:
What is the syntax of the ternary operator in these languages?
All four use:
condition ? first : second
for the ternary if operator.
If all four use ?, it is natural that in operators which are shortcuts of the ternary operator they use ?. But in Python the bar of introducing ? is higher.
It's also noteworthy that they all offer "&&" and "||" as short circuiting "and" and "or" operators. When you have that pattern established, then "??" fits right in. With Python's only spelling for the logical operators being "and" and "or", the cryptic unpronounceable nature of "??" becomes much harder to ignore. "a and b" -> pronounced "a and b" "a or b" -> pronounced "a or b" "a ?? b" -> pronounced "a <what??> b" The only potentially pronounceable versions I've been able to come up with are a fair bit longer: "a if def else b" -> pronounced "a if defined, else b" "a if ?? is not None else b" -> pronounced "a if the leftmost operand is not None, else b" "a if ?? is None else ??.b" -> pronounced "a if the leftmost operand is None, else the leftmost operand dot b" (The last two examples there are a version where "??" appearing in either the condition expression or the RHS of a conditional expression would cause the leftmost operand to be eagerly evaluated, placed in a hidden temporary variable and then referenced multiple times as a subexpression. A similar construct could then also be used in filter expressions in comprehensions to refer back to the loop's result clause: "[f(x) for x in iterable if ?? is not None]". It's still magical and hard to look up syntax, but "??" as a magic placeholder to say "Reference the leftmost operand in the current expression here, but still only evaluate it once" seems nicer to me than using it as a cryptic binary operator) Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
29.11.17 14:39, Nick Coghlan пише:
"a if def else b" -> pronounced "a if defined, else b"
I understand "a if defined, else b" as try: result = a except (NameError, AttributeError, LookupError): result = b The problem is that None is not undefined. This is a regular value. Seems it is not so special in Python as NULL or undef in other languages. Python even don't have a special purposed NullPointerException (or NoneError).
On 29.11.2017 9:08, Steven D'Aprano wrote: > On Tue, Nov 28, 2017 at 12:31:06PM -0800, Raymond Hettinger wrote: >>> I also cc python-dev to see if anybody here is strongly in favor or against this inclusion. >> Put me down for a strong -1. The proposal would occasionally save a >> few keystokes but comes at the expense of giving Python a more Perlish >> look and a more arcane feel. > I think that's an unfair characterisation of the benefits of the PEP. > It's not just "a few keystrokes". > > Ironically, the equivalent in Perl is // which Python has used for > truncating division since version 2.4 or so. So if we're in danger of > looking "Perlish", that ship has sailed a long time ago. > > Perl is hardly the only language with null-coalescing operators -- we > might better describe ?? as being familiar to C#, PHP, Swift and Dart. > That's two mature, well-known languages and two up-and-coming languages. My experience with these operators in C# says: * They do save "more than a few keystrokes". Even more importantly, they allow to avoid double evaluation or the need for a temporary variable workaround that are inherent in "<expr> if <expr> else <alternative>" * (An alternative solution for the latter problem would be an assignment expression, another regularly rejected proposal.) * They make it temptingly easy and implicit to ignore errors. * They are alien to Python's standard semantics on search failure which is to raise an exception rather than return None > > [...] >> timeout ?? local_timeout ?? global_timeout > As opposed to the status quo: > > timeout if timeout is not None else (local_timeout if local_timeout is not None else global_timeout) > > Or shorter, but even harder to understand: > > (global_timeout if local_timeout is None else local_timeout) if timeout is None else timeout > > I'd much prefer to teach the version with ?? -- it has a simple > explanation: "the first of the three given values which isn't None". The > ?? itself needs to be memorized, but that's no different from any other > operator. The first time I saw ** I was perplexed and couldn't imagine > what it meaned. > > Here ?? doesn't merely save a few keystrokes, it significantly reduces > the length and complexity of the expression and entirely cuts out the > duplication of names. > > If you can teach > > timeout or local_timeout or global_timeout > > then you ought to be able to teach ??, as it is simpler: it only > compares to None, and avoids needing to explain or justify Python's > truthiness model. > > >> 'foo' in (None ?? ['foo', 'bar']) > If you can understand > > 'foo' in (False or ['foo', 'bar']) > > then surely you can understand the version with ??. > > >> requested_quantity ?? default_quantity * price > Again: > > (default_quantity if requested_quantity is None else requested_quantity) * price > > > I'd much prefer to read, write and teach the version with ?? over the > status quo. > > -- Regards, Ivan
On Thu, Nov 30, 2017 at 08:02:08PM +0300, Ivan Pozdeev via Python-ideas wrote:
My experience with these operators in C# says: * They do save "more than a few keystrokes". Even more importantly, they allow to avoid double evaluation or the need for a temporary variable workaround that are inherent in "<expr> if <expr> else <alternative>" * (An alternative solution for the latter problem would be an assignment expression, another regularly rejected proposal.) * They make it temptingly easy and implicit to ignore errors.
How?
* They are alien to Python's standard semantics on search failure which is to raise an exception rather than return None
Alien, like this? py> mo = re.match(r'\d:', 'abc') py> mo is None True Besides, who said this is limited to searching? I don't remember even a single example in the PEP being about searching. -- Steve
participants (11)
-
Antoine Pitrou
-
Chris Barker
-
David Mertz
-
Elazar
-
Ivan Pozdeev
-
Kirill Balunov
-
Lele Gaifax
-
Nick Coghlan
-
Paul Moore
-
Serhiy Storchaka
-
Steven D'Aprano