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

Steven D'Aprano steve at pearwood.info
Tue Jul 31 13:46:47 EDT 2018


On Mon, Jul 30, 2018 at 12:41:20PM -0500, Abe Dillon wrote:

[Rhodri James]
> > On 29/07/18 16:12, Abe Dillon wrote:
> >  > spam?.eggs.cheese.aardvark  # why would you ever do this?
> > 
> > If you knew that if you really have something in "spam", your program
> > guarantees it will have an "eggs" attribute with a "cheese" attribute, etc,
> > you just don't know if "spam" is not None.  It's the same insider knowledge
> > you would use if you wrote it out as
> > 
> > spam.eggs.cheese.aardvark if spam is not None else None
> 
> 
> That's not the equivalent as described in PEP 505. 

Yes it is. Rhodri is correct, although I admit that I hadn't realised 
this point myself until he pointed it out. (That is why until now I've 
been writing examples like "spam?.eggs?.cheese?.aardvark" which is 
redundant.)

The abstract says:

    The "None-aware attribute access" operator ?. ("maybe dot")
    evaluates the complete expression if the left hand side 
    evaluates to a value that is not None

and later on the PEP says:

    When a None-aware operator is present, the left-to-right 
    evaluation may be short-circuited. For example, 
    await a?.b(c).d?[e] is evaluated:

    _v = a
    if _v is not None:
        _v = _v.b
        _v = _v(c)
        _v = _v.d
        if _v is not None:
            _v = _v[e]
    await _v


I admit the example isn't the clearest. The inclusion of "await" doesn't 
seem helpful to me (if anything, the opposite, since "await None" will 
fail) and perhaps it would be clearer to write it as:

    _v = a
    if _v is not None:
        _v = _v.b(c).d
        if _v is not None:
            _v = _v[e]


The PEP also says:

    Parenthesised expressions are handled by the atom rule (not 
    shown above), which will implicitly terminate the short-
    circuiting behaviour of the above transformation.

which again isn't too clear, and the example given seems complicated 
enough to obfuscate the point rather than illustrate it, but if I'm 
reading it correctly, the behaviour you expected would have to be 
written as

    (spam?.eggs).cheese.aardvark

which would likely fail since None has no cheese attribute.

The bottom line is that in any unparenthesized chain of maybe-dot and 
maybe-subscript operations, only the first needs to be "maybe" as that 
will short-circuit the rest of the expression.

Figuratively speaking, it is as if we had:

    spam?(.eggs.cheese.aardvark)

where the () are used for grouping, not function call.



-- 
Steve


More information about the Python-ideas mailing list