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
[email protected]
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/