On 26.05.20 14:10, David Mertz wrote:

All of those uses, including those where you say otherwise, treat None
as a sentinel. In the iter() case, the optional seconds argument is
*called* 'sentinel'. Guido recently mentioned that he had forgotten
the two argument form of iter(), which is indeed funny... But useful.

Maybe we have a different understanding of "sentinel" in this context. I
understand it as an auxiliary object that is used to detect whether the
user has supplied an argument for a parameter or not. So if the set of
possible (meaningful) arguments is "A" then the sentinel must not be an
element of A. So in cases where None has meaning as an argument it can't
act as a sentinel. `iter` is probably implemented via varargs but if it
was designed to take a `sentinel=` keyword parameter then you'd need a
dedicated sentinel object since the user can supply *any* object as the
(user-defined) sentinel, including None:

    >>> list(iter([1, 2, None, 4, 5].pop, None))
    [5, 4]

Well, ok functions.reduce() really does make it's own sentinel in
order to show NONE as a "plain value". So I'll grant that one case is
slightly helped by a hypothetical 'undef'.

The NumPy, deque, and lru_cache cases are all ones where None is a
perfect sentinel and the hypothetical 'undef' syntax would have zero
value.

For both `deque` and `lru_cache` None is a sensible argument so it can't
act as a sentinel. It just happens that these two cases don't need to
check if an argument was supplied or not, so they don't need a sentinel.
For the Numpy cases, `np.sum` and `np.diff`, None does have a meaning
from user perspective, so they need a dedicated sentinel (which is
`np._NoValue`). If `keepdims` is not supplied, it won't be passed on to
sub-classes; if it is set to None then the sub-class receives
`keepdims=None` as well:

    >>> class Test(np.ndarray):
    ...     def sum(self, **kwargs):
    ...         return kwargs
    ...
    >>> a = Test(0)
    >>> np.sum(a)
    {'axis': None, 'out': None}
    >>> np.sum(a, keepdims=None)
    {'axis': None, 'out': None, 'keepdims': None}

For `np.diff`, if no argument is provided for `append` (or `prepend`)
then nothing is appended (prepended), otherwise the supplied value is
used (including None):

    >>> np.diff([1, 2])
    array([1])
    >>> np.diff([1, 2], append=None)
    TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

For `np.concatenate` None is a meaningful argument to `axis` since it
will flatten the arrays before concatenation.


I was wondering if anyone would mention Pandas, which is great, but in
many ways and abuse of Pythonic programming. There None in an
initializing collection (often) gets converted to NaN, both of which
mean "missing", which is something different. This is kind of an abuse
of both None and NaN... which they know, and introduced an
experimental pd.NA for exactly that reason... Unfortunately, so far,
actually using of.NA is cumbersome, but hopefully that gets better
next version.
I wouldn't say it's an abuse, it's an interpretation of these values.
Using NaN has the clear advantage that it fits into a float array so
it's memory efficient.

Within actual Pandas and function parameters, None is always a sentinel.

On Tue, May 26, 2020, 4:48 AM Dominik Vilsmeier
<dominik.vilsme...@gmx.de <mailto:dominik.vilsme...@gmx.de>> wrote:

    On 26.05.20 06:03, David Mertz wrote:

    On Mon, May 25, 2020, 11:56 PM Christopher Barker

        well, yes and no. this conversation was in the context of
        "None" works fine most of the time.


    How many functions take None as a non-sentinel value?! How many
    of that tiny numbers do so only because they are poorly designed.

    None already is an excellent sentinel. We really don't need
    others. In the rare case where we really need to distinguish None
    from "some other sentinel" we should create our own special one.

    The only functions I can think of where None is appropriately
    non-sentinel are print(), id(), type(), and maybe a couple other
    oddball special ones.

    Seriously, can you name a function from the standard library or
    another popular library where None doesn't have a sentinel role
    as a function argument (default or not)?

    * From the builtins there is `iter` which accepts a sentinel as
    second argument (including None).
    * `dataclasses.field` can receive `default=None` so it needs a
    sentinel.
    * `functools.reduce` accepts None for its `initial` parameter
    (https://github.com/python/cpython/blob/3.8/Lib/functools.py#L232).
    * There is also
    
[`sched.scheduler.enterabs`](https://github.com/python/cpython/blob/v3.8.3/Lib/sched.py#L65)
    where `kwargs=None` will be passed on to the underlying `Event`.

    For the following ones None could be a sentinel but it's still a
    valid (meaningful) argument (different from the default):

    * `functools.lru_cache` -- `maxsize=None` means no bounds for the
    cache (default is 128).
    * `collections.deque` -- `maxlen=None` means no bounds for the
    deque (though this is the default).

    Other example functions from Numpy:

    *
    
[`numpy.concatenate`](https://numpy.org/doc/1.18/reference/generated/numpy.concatenate.html)
    -- here `axis=None` means to flatten the arrays before
    concatenation (the default is `axis=0`).
    * Any function performing a reduction, e.g.
    [`np.sum`](https://numpy.org/doc/1.18/reference/generated/numpy.sum.html)
    -- here if `keepdims=` is provided (including None) then it will
    passed to the `sum` method of ndarray-sub-classes, otherwise not.
    *
    [`np.diff`](https://numpy.org/doc/1.18/reference/generated/numpy.diff.html)
    supports prepending / appending values prior to the computation,
    including None (though that application is probably rare).

    _______________________________________________
    Python-ideas mailing list -- python-ideas@python.org
    <mailto:python-ideas@python.org>
    To unsubscribe send an email to python-ideas-le...@python.org
    <mailto:python-ideas-le...@python.org>
    https://mail.python.org/mailman3/lists/python-ideas.python.org/
    Message archived at
    
https://mail.python.org/archives/list/python-ideas@python.org/message/U4U7X36COLQ776LRB4O6O4BEXDXFWHJK/
    Code of Conduct: http://python.org/psf/codeofconduct/


_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/CITAZRZXLAUAHBFPOKMFQZEBJ34OWJBS/
Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/DQZBWJDR3ED6A5UPT2454VEGN3W5XE5Q/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to