On Wed, Nov 02, 2016 at 10:22:56PM -0400, Kyle Lahnakoski wrote:
> 
> On 11/2/2016 2:30 PM, Zero Piraeus wrote:
> >
> >If I write something like obj.attr, the failure mode I care about is that
> >obj has no attribute attr, rather than that obj is specifically None (or
> >one of a defined group of somewhat Nonelike objects).
> >
> 
> I agree with this understanding. The problem with None-coalescing is 
> it doesn't consider where None came from.

I don't see why you think that's a problem. What does it matter where 
None comes from? It seems to me that the important factor is what you 
intend to do with it, not where it came from.

If I write this code:

    None if obj is None else obj.attr


what difference does it make where None came from? The important thing 
is that I'm treating obj == None as a known condition.

Now if you *don't* want to treat None specially, then of course this 
feature will be of no interest to you. This feature isn't aimed at you, 
it is aimed at the many people who do treat None specially.


If you prefer:

    # obj is known to be a specific type, but attr may be None
    None if obj.attr is None else obj.attr.flange()


That would be written 

    obj.attr?.flange()


in the proposed new syntax, and obj.attr will only be evaluated once.

But note that this is quite different from the situation that Zero is 
talking about. In Zero's code, he prefers for obj.attr to not exist at 
all rather than setting it to None. So rather than this:

    None if obj.attr is None else obj.attr.flange()


he might write something similar to this:

    None if not hasattr(obj, 'attr') else obj.attr.flange()


(or at least *I* might write that, under the circumstances Zero refers 
to.) And here's the good bit: under this proposal, we might 
simplify it to this:

    getattr(obj, 'attr', None)?.flange()


which handles three cases for the price of one:

- obj.attr doesn't exist at all, in which case return None;
- obj.attr exists and is None, in which case return None;
- obj.attr exists and is not None, in which case call its 
  flange() method.


To me, having a compact and expressive syntax to write that is very 
attractive.


> I suspect enumerating the source 
> of None values will reveal the majority of them are a result of 
> `getattr(obj, attr)` returning None (or obj.get(attr) returning None).

Have you read the PEP? If you do, you'll see that the author has already 
collected potential examples of use from the standard library:

https://github.com/python/peps/blob/master/pep-0505/find-pep505.out


Looking at those examples of code, I don't think it is likely that the 
majority (or even a large minority) are the result of getattr.

But even if they are, what difference does it make?


> If your code deals with annotated objects, rather than strictly typed 
> objects, you will have many instances of attributes resolving to None.
> Making specific classes for each of the annotations, or combinations of 
> annotations, is prohibitive, so you don't.  Rather, you use a few 
> general types and set some attributes to None to indicate a property is 
> not-relevant-for-this-object.

I'm afraid I don't understand this.


> None checks are type checks. They are late type checks .

Call it a type check if you like, but type check or value check or 
"rhubarb", whatever you want to call it, any time you test for None:

    if expression is None ...

there's a reasonable chance that the None-aware operators may help you 
write better, more expressive code without falling into the trap of 
using `or` to handle None. Not in *all* cases, but I think often enough.


-- 
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/

Reply via email to