Mark Storer
Mark Storer

Reputation: 15868

Difference between None and <no value>

I'm familiar with Java's null and C++'s nullptr, plus similar concepts from several scripting languages. None looks remarkably like Python's version of that same old theme.

And then I ran across this function declaration:

 numpy.amin(a, axis=None, out=None, keepdims=<no value>, initial=<no value>, where=<no value>)

What's the difference between None and <no value>? I'm guessing this is just a documentation generation thing when there's no defined default, but then why not just not list a default at all?

Upvotes: 3

Views: 1794

Answers (2)

Martijn Pieters
Martijn Pieters

Reputation: 1121834

It's just a documentation thing, there is no such concept in Python itself.

Take into account that None in itself is also a valid object. Sometimes you want to accept None as a valid value for an argument, so you can't use that as the default value for an optional parameter. You wouldn't be able to distinguish between the default None and someone passing in None explicitly, since it's a singleton!

If I needed to define such a function, I'd use a different singleton sentinel. You can create one from just about anything, but simplest is to use an object() instance:

_sentinel = object()

def foo(bar, baz=_sentinel):
    if baz is not _sentinel:
        # baz has a defined value, because it is
        # not a reference to the sentinel

And perhaps I'd also use <no value> in the documentation to indicate that baz is optional. It all depends on the local conventions. The Python documentation itself uses [...] around optional arguments, for example.

numpy.amin() is actually a proxy function; it delegates the actual work either to numpy.minimum() (via ufunc.reduce(), or, if the first argument is a subclass that implements an amin() method, to that method of the subclass. Because the latter should be able to set their own defaults, using a sentinel lets the numpy.amin() implementation pass on only those keyword arguments that actually were given an explicit value, without dictating what kind of sentinel the subclass .amin() implementations should use or what types they accept.

The Numpy project actually created their own singleton class to act as a sentinel so they could give the object a helpful repr() output:

>>> from numpy._globals import _NoValue
>>> _NoValue
<no value>
>>> type(_NoValue)
<class 'numpy._globals._NoValueType'>

Finally, None should not be compared with null or nullptr. None is a singleton object, something to reference instead of another object. null and nullptr are used to signal the absence of a reference, and can be passed around like other scalar values. You can't do this in Python, where everything is a valid reference to an object. (At most, you get a NameError or UnboundLocal exception if you tried to use a name that hasn't been bound to yet in its namespace).

Upvotes: 8

hpaulj
hpaulj

Reputation: 231385

The code for the np._NoValue class:

class _NoValueType(object):
    """Special keyword value.

    The instance of this class may be used as the default value assigned to a
    deprecated keyword in order to check if it has been given a user defined
    value.
    """
    __instance = None
    def __new__(cls):
        # ensure that only one instance exists
        if not cls.__instance:
            cls.__instance = super(_NoValueType, cls).__new__(cls)
        return cls.__instance

    # needed for python 2 to preserve identity through a pickle
    def __reduce__(self):
        return (self.__class__, ())

    def __repr__(self):
        return "<no value>"
File:           /usr/local/lib/python3.6/dist-packages/numpy/_globals.py
Type:           type

Upvotes: 2

Related Questions