[Python-ideas] PEP 505: None-aware operators

C Anthony Risinger c at anthonyrisinger.com
Mon Jul 23 12:19:20 EDT 2018


On Mon, Jul 23, 2018 at 7:46 AM, Grégory Lielens <gregory.lielens at gmail.com>
wrote:

>  Paul Moore wrote:
>>
>> This is my impression, as well. It seems like something that's helpful
>> in dealing with unstructured object hierarchies with lots of optional
>> attributes - which is where JSON tends to be used.
>>
>> But given that, I'm really much more interested in seeing the new
>> operators compared against a well-written "JSON object hierarchy
>> traversal" library than against raw Python code.
>>
>
> Good point, I did not think about that when suggesting to give some
> context, but indeed if it's linked to a library in particular, there is
> always the possibility to choose another object than None as the "nothing
> here" marker.
>
>From what I gather, disallowing reassignment all but cements None as the
"nothing here" marker (the originally intent?), _especially_ when "nothing
here" is candidate for replacement by a more appropriate, type- or domain-
or context-specific "nothing here" marker. Imbuing None with any other
meaning brings nothing but headache. It's an attractive nuisance. None is
None is None, there can be only one! You don't know what it is, only that
it's not anything else. What possible meaning can such an object usefully
have in an application built on disparate libraries with their own ideas on
the matter?

Every API I've used (apologies for coming up blank on a concrete example!)
granting None meaning is awkward to consume. `.get()` interfaces are less
useful (must carry your own internal sentinels) or more try/except blocks
are required to achieve the same end (not a bad thing per se, but
a diminished experience to be sure). Early APIs I wrote in this "well it's
None, but but but, with this convenient meaning, see?! SEE??"-style were
later regarded -- quite thoroughly -- as a bad idea by myself, my peers,
and downstream consumers.

I'd personally use these new operators both frequently and judiciously.
They align very well with a "set 'em up and knock 'em down"-style I use:
normalized, progressively conditioned input values fast-followed by
aggressive short-circuits and clear early returns. IME this pattern
generates clean, readable, and performant code. Honestly the
short-circuiting capability alone is enough to sell me :-) This PEP would
find legitimate use by me every day. I'm not 100% sold on `?[` (then again,
attributes are pulled from an object namespace via `?.` and namespaces are
containers by definition) but `?.` and `??` deliver immense value.

Not sure if useful, but this discussion reminds me of a pattern prevalent
in the Elixir community. They use `?` and `!` in function definitions to
denote variants differing only on return behavior (not function clauses!
This is by convention only, they're entirely new functions with a symbol in
their name). It looks something like this:

# Default function.
# Return a tuple {interesting-or-nil, error-or-nil}.
def open(path) do ... end

# Maybe variant.
# Return a boolean, or less often, interesting-or-nil (replaces `is_` or
`can_` methods in Python).
def open?(path) do ... end

# Forceful variant.
# Return interesting or die trying (inverse of `.get()` methods in Python;
raising is not the default expectation in Elixir).
def open!(path) do ... end

The `?.`-operator reminds me of this. It offers to perform an extremely
common operation (simple attribute access) while short-circuiting on the
most frequently triggered guard condition (AttributeError).

I don't think the utility here is restricted to deeply nested JSON
`loads()` or one-off scripts. It better aligns the community on semantics,
encouraging more idiomatic -- and uniform! -- interactions with None.

-- 

C Anthony
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20180723/68436deb/attachment-0001.html>


More information about the Python-ideas mailing list