Reputation: 15868
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
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
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