On Sat, Oct 29, 2016 at 02:52:42PM +1000, Nick Coghlan wrote:
On 29 October 2016 at 04:08, Mark Dickinson firstname.lastname@example.org wrote:
On Fri, Oct 28, 2016 at 9:30 AM, Nick Coghlan email@example.com wrote:
[...] the current practicises of:
- obj is not None (many different use cases)
- obj is not Ellipsis (in multi-dimensional slicing)
Can you elaborate on this one? I don't think I've ever seen an `is not Ellipsis` check in real code.
It's more often checked the other way around: "if Ellipsis is passed in, then work out the multi-dimensional slice from the underlying object"
And that reflects the problem Paul and David highlighted: in any *specific* context, there's typically either only one sentinel we want to either propagate or else replace with a calculated value, or else we want to handle different sentinel values differently, which makes the entire concept of a unifying duck-typing protocol pragmatically dubious, and hence calls into question the idea of introducing new syntax for working with it.
On the other hand, if you try to do this as an "only None is special" kind of syntax, then any of the *other* missing data sentinels (of which we have 4 in the builtins alone, and 5 when you add the decimal module) end up being on much the same level as "arbitrary sentinel objects" in the draft PEP 531, which I would consider to be an incredibly poor outcome for a change as invasive as adding new syntax: https://www.python.org/dev/peps/pep-0531/#arbitrary-sentinel-objects
Hmmm. I see your point, but honestly, None *is* special. Even for special objects, None is even more special. Here are your examples again:
* obj is not None (many different use cases) * obj is not Ellipsis (in multi-dimensional slicing) * obj is not NotImplemented (in operand coercion) * math.isnan(value) * cmath.isnan(value) * decimal.getcontext().is_nan(value)
Aside from the first, the rest are quite unusual:
- Testing for Ellipsis occurs in __getitem__, and not even always then.
- Testing for NotImplemented occurs in operator dunders, rarely if ever outside those methods. (You probably should never see NotImplemented except in an operator dunder.)
In both cases, this will be a useful feature for the writer of the class, not the user of the class.
- Testing for NAN is really only something of interest to those writing heavily numeric code and not even always then.
You can go a LONG way with numeric code by just assuming that x is a regular number, and leaving NANs for "version 2". Especially in Python, which typically raises an exception where it could return a NAN. In other words, its quite hard to generate an unexpected NAN in Python.
So these examples are all quite special and of very limited applicability and quite marginal utility. My guess is that the majority of programmers will never care about these cases, and of those who do, they'll only need it quite rarely. (We use classes far more often than we write classes.)
But None is different. My guess is that every Python programmer, from the newest novice to the most experienced guru, will need to check for None, and likely frequently.
So my sense is that of all the use-cases for existence checking divide into two categories:
- checking for None (> 95%) - everything else (< 5%)
I did a very rough search of the Python code on my system and found this:
is [not] None: 10955
is [not] Ellipsis: 13
is [not] NotImplemented: 285
is_nan( / isnan( : 470
which is not far from my guess.