Issue 24145: Support |= for parameters in converters (original) (raw)

Created on 2015-05-08 12:33 by larry, last changed 2022-04-11 14:58 by admin.

Messages (5)

msg242756 - (view)

Author: Larry Hastings (larry) * (Python committer)

Date: 2015-05-08 12:33

Some "format units" provided by PyArg_ParseTuple() are exactly the same as others, except that they also accept the value None. For example, "s" and "z" are exactly the same, except "z" accepts None and "s" does not. The same goes for "s*" and "z*", or "s#" and "z#".

To tell an Argument Clinic converter which types of objects it should accept, one would pass in the "accept" named parameter. We now use this facility for the "also accept None" format units. "z" is the same as "s", except that for "z" you add NoneType to the list of types passed in for "accept". Like so:

str1: str()                       # format unit 's'
str2: str(accept={str, NoneType}) # format unit 'z'

The trick here is, the default value for the 'accept' parameter for the str() converter is {str}. But you have to know that in order to add NoneType to it.

It'd be nice if there were some way of saying "take the existing default value for parameter X, and add value Y to it". Then for the "accept" parameter you could just add NoneType to it. You might say, "yeah, but Python doesn't have anything like that". To which I say, Argument Clinic isn't Python. It leverages Python syntax (using ast.parse) but we need not be bound by what Python does. We could maybe add a little syntax or play with the semantics to add this functionality.

We discussed this on c.l.p-d a little, and some folks took the opportunity to play a little syntax golf with the idea. (Everybody who participated in the thread writ large got Cc'd on this bug, congratulations, you're welcome!) Ultimately there was only one syntax I liked, which (no surprise) was one I suggested:

str2: str(accept|={NoneType})

accept's default value is a set, and sets use | as the union operator. And Python actually has a |= statement, although it doesn't work in function calls like that. But that means readers unfamiliar with Argument Clinic should be able to quickly intuit what the syntax means. It also meant I could use the tokenize module to do a proper job of the implementation.

So I ask you: do we want this? Advantages and disadvantages as I see them:

Take a look at the diffs and decide whether the new syntax is an improvement. (You can look at the implementation too, of course, if you're curious. But IMO the implementation is fine, and ready to go in if we want it.)

msg242758 - (view)

Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer)

Date: 2015-05-08 13:00

For now str(accept={str, NoneType}) is used only 14 times in 6 files in 5 modules. The "z" format unit is used also in still not converted modules _codecs (a lot of sites), _locale, mmap, _multiprocessing, and _socket. Current syntax doesn't look so ugly for me. I would wait until we converted more modules and implemented more converters that don't match existing format units.

Alternative syntax can be "str | NoneType" (without the accept parameter at all).

msg242759 - (view)

Author: Raymond Hettinger (rhettinger) * (Python committer)

Date: 2015-05-08 13:00

To my eyes, the current set notation form more clearly expresses its intentions than the |= notation. Readability counts.

I agree the |= is a startling syntax that looks weird enough to cause a mental hiccup when reading it.

So, put me down for a -1. The mild benefit isn't worth it.

msg242784 - (view)

Author: Alyssa Coghlan (ncoghlan) * (Python committer)

Date: 2015-05-08 23:05

Aye, it occurs to me now that introducing the implicit form trades a "write time" lookup (where you have to override the converter defaults explicitly), for a "read time" lookup (where you need to mentally add the defaults to understand the modified accept clause)

As a result, I think "explicit is better than implicit" wins, at least for now. If we decide after we have more experience that the repetition of the defaults when overriding them really is a problem, then it's possible to revisit that decision in the 3.6 time frame.

msg242801 - (view)

Author: Tal Einat (taleinat) * (Python committer)

Date: 2015-05-09 09:01

Well, the main reasons I'm +1 on the "|=" feature (regardless of specific syntax) are:

  1. the intent is much clearer: e.g. also accept None, nothing else special going on
  2. much easier maintenance if the default set of accepted types ever changes

Also, this is one of the cases where I think that DRY defeats "explicit is better than implicit". As another example, in some hypothetical code, if there was a module constant "DEFAULT_FLAGS = A | B | C", I would prefer later to use "flags = DEFAULT_FLAGS | D" rather than "flags = A | B | C | D".

History

Date

User

Action

Args

2022-04-11 14:58:16

admin

set

github: 68333

2018-06-14 10:28:23

taleinat

set

nosy: - taleinat

2015-05-09 09:01:50

taleinat

set

messages: +

2015-05-08 23:05:42

ncoghlan

set

messages: +

2015-05-08 13:00:41

rhettinger

set

nosy: + rhettinger
messages: +

2015-05-08 13:00:21

serhiy.storchaka

set

messages: +

2015-05-08 12:33:12

larry

create