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

Steven D'Aprano steve at pearwood.info
Wed Aug 1 09:12:35 EDT 2018


On Wed, Aug 01, 2018 at 11:03:05AM +0100, Jonathan Fine wrote:

[...]
> After my last post, you wrote
> > None.?__str__
> > produces None, even though None has a __str__ attribute.
> 
> This surprises me. But I think it follows from the rules in
> https://www.python.org/dev/peps/pep-0505/#the-maybe-dot-and-maybe-subscript-operators

Correct. None?.__str__ is equivalent to:

    _v = None
    if _v is not None:
        _v = _v.__str__
    return _v

(except no actual _v variable is created, and it is not literally a 
return statement).


> My initial reading of
> >>> a ?. b
> was that if 'a' didn't have a 'b' attribute, then the result was None,
> whatever the string 'b'.
> 
> In other words, the same as
> >> getattr(a, name, None)

No. PEP 505 is for None-aware operators. It spends considerable time 
explaining that it treats None as special. It does not catch 
AttributeError from missing attributes.

    (45)?.upper()

will fail with AttributeError, same as (45).upper() does.



> The abstract to PEP 505 writes
> ===
> 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
> ===
> 
> This is, of course, informal prose. I'm now reading it carefully.
> Here's a specific example.
> 
> >>> (42).__str__
> <method-wrapper '__str__' of int object at 0x99f480>
> >>> (42).str
> Traceback (most recent call last):
> AttributeError: 'int' object has no attribute 'str'
> >>> (42) ?. str
> 
> I don't see how to apply the prose in the abstract to this last
> example. The left hand side is not None, so we "evaluate the complete
> expression". On one reading, this is a recursion.

The phrasing could be clearer.

Since 42 is not None, it evaluates (42).str which of course will 
fail with AttributeError. To be specific, it is equivalent to something 
like this pseudo-code:

    _v = 42
    if _v is not None:
        _v = _v.str
    return _v

(The same disclaimer about _v and return apply as earlier.)




-- 
Steve


More information about the Python-ideas mailing list