在 Python 中,'null' 对象是单例None
。
检查 “无效” 的最佳方法是使用身份运算符, is
:
if foo is None:
...
它不像其他语言那样被称为 null,但是None
。此对象始终只有一个实例,因此,如果需要,可以检查x is None
等效性x is None
(身份比较)而不是x == None
。
None
,Python 是 null? Python 中没有null
,而是None
。如前所述,最准确的方法是测试某些东西已被赋予None
作为值是使用is
identity 运算符,它运行时测试两个变量引用同一个对象。
>>> foo is None
True
>>> foo = 'bar'
>>> foo is None
False
None
None
是NoneType
类的唯一实例,并且实例化该类的任何进一步尝试都将返回相同的对象,这使得None
成为单例。 Python 的新手经常会看到提及NoneType
错误消息,并想知道它是什么。这是我个人的看法是,这些消息可能只是简单地提到None
以名,因为我们很快就会看到, None
叶的小房间歧义。所以,如果你看到一些TypeError
消息提到NoneType
不能做到这一点还是不能做到这一点,只知道它只是一个None
正被在某种程度上使用,它不能。
此外, None
是一个内置常量,只要你启动 Python,它就可以在任何地方使用,无论是在模块,类还是函数中。 NoneType
相比之下是不是,你需要先通过查询得到它的引用None
为它的类。
>>> NoneType
NameError: name 'NoneType' is not defined
>>> type(None)
NoneType
您可以使用 Python 的标识函数id()
检查None
的唯一性。它返回分配给对象的唯一编号,每个对象都有一个。如果两个变量的 id 相同,那么它们实际上指向同一个对象。
>>> NoneType = type(None)
>>> id(None)
10748000
>>> my_none = NoneType()
>>> id(my_none)
10748000
>>> another_none = NoneType()
>>> id(another_none)
10748000
>>> def function_that_does_nothing(): pass
>>> return_value = function_that_does_nothing()
>>> id(return_value)
10748000
None
不能被覆盖在更旧版本的 Python(2.4 之前)中,可以重新分配None
,但不能再重新分配。甚至不是作为类属性或在函数的范围内。
# In Python 2.7
>>> class SomeClass(object):
... def my_fnc(self):
... self.None = 'foo'
SyntaxError: cannot assign to None
>>> def my_fnc():
None = 'foo'
SyntaxError: cannot assign to None
# In Python 3.5
>>> class SomeClass:
... def my_fnc(self):
... self.None = 'foo'
SyntaxError: invalid syntax
>>> def my_fnc():
None = 'foo'
SyntaxError: cannot assign to keyword
因此可以安全地假设所有None
引用都是相同的。没有 “自定义” None
。
None
使用is
运算符在编写代码时,您可能会尝试像这样测试Noneness :
if value==None:
pass
或者像这样测试虚假
if not value:
pass
您需要了解其含义以及为什么明确这一点通常是一个好主意。
None
为什么这样做
value is None
而不是
value==None
第一个相当于:
id(value)==id(None)
而表达式value==None
实际上是这样应用的
value.__eq__(None)
如果值真的是None
那么你将得到你所期望的。
>>> nothing = function_that_does_nothing()
>>> nothing.__eq__(None)
True
在大多数常见情况下,结果将是相同的,但__eq__()
方法打开了一扇门,无法保证准确性,因为它可以在类中被覆盖以提供特殊行为。
考虑这个课程。
>>> class Empty(object):
... def __eq__(self, other):
... return not other
所以你在None
上尝试它并且它有效
>>> empty = Empty()
>>> empty==None
True
但是它也适用于空字符串
>>> empty==''
True
但是
>>> ''==None
False
>>> empty is None
False
None
作为布尔值以下两个测试
if value:
# do something
if not value:
# do something
实际上被评估为
if bool(value):
# do something
if not bool(value):
# do something
None
是 “falsey”,意味着如果转换为布尔值,它将返回False
,如果应用not
运算符,它将返回True
。但请注意,它不是None
独有的属性。除了False
本身之外,该属性由空列表,元组,集合,dicts,字符串以及 0 以及实现__bool__()
魔术方法的类中的所有对象__bool__()
以返回False
。
>>> bool(None)
False
>>> not None
True
>>> bool([])
False
>>> not []
True
>>> class MyFalsey(object):
... def __bool__(self):
... return False
>>> f = MyFalsey()
>>> bool(f)
False
>>> not f
True
因此,当以下列方式测试变量时,请特别注意您在测试中包含或排除的内容:
def some_function(value=None):
if not value:
value = init_value()
在上面,你的意思是当值专门设置为None
时调用init_value()
,或者你的意思是设置为0
的值,或空字符串,或空列表也应该触发初始化。就像我说的那样,要小心。因为 Python 中的情况通常比隐式更好 。
None
None
用作信号值 None
在 Python 中具有特殊状态。它是最受欢迎的基准值,因为许多算法将其视为特殊值。在这种情况下,它可以用作标志,表示条件需要一些特殊处理(例如设置默认值)。
您可以将None
分配给函数的关键字参数,然后显式测试它。
def my_function(value, param=None):
if param is None:
# do something outrageous!
您可以在尝试获取对象的属性时将其作为默认值返回,然后在执行特殊操作之前显式测试它。
value = getattr(some_obj, 'some_attribute', None)
if value is None:
# do something spectacular!
默认情况下,字典的get()
方法在尝试访问不存在的键时返回None
:
>>> some_dict = {}
>>> value = some_dict.get('foo')
>>> value is None
True
如果您尝试使用下标表示法来访问它,则会引发KeyError
>>> value = some_dict['foo']
KeyError: 'foo'
同样,如果您尝试弹出不存在的项目
>>> value = some_dict.pop('foo')
KeyError: 'foo'
您可以使用通常设置为 “ None
的默认值进行抑制
value = some_dict.pop('foo', None)
if value is None:
# booom!
None
用作标志和有效值当不被认为是有效值时,上述None
应用适用,但更像是做特殊事情的信号。然而,在某些情况下,有时候知道None
来自哪里是很重要的,因为即使它被用作信号,它也可能是数据的一部分。
当您使用getattr(some_obj, 'attribute_name', None)
查询对象getattr(some_obj, 'attribute_name', None)
返回None
不会告诉您您尝试访问的属性是否设置为None
或者该对象是否完全不存在。从some_dict.get('some_key')
这样的字典访问密钥时,你不知道some_dict['some_key']
是否缺失,或者它是否只是设置为None
。如果您需要该信息,通常的处理方法是直接尝试从try/except
结构中访问属性或键:
try:
# equivalent to getattr() without specifying a default
# value = getattr(some_obj, 'some_attribute')
value = some_obj.some_attribute
# now you handle `None` the data here
if value is None:
# do something here because the attribute was set to None
except AttributeError:
# we're now hanling the exceptional situation from here.
# We could assign None as a default value if required.
value = None
# In addition, since we now know that some_obj doesn't have the
# attribute 'some_attribute' we could do something about that.
log_something(some_obj)
与 dict 类似:
try:
value = some_dict['some_key']
if value is None:
# do something here because 'some_key' is set to None
except KeyError:
# set a default
value = None
# and do something because 'some_key' was missing
# from the dict.
log_something(some_dict)
以上两个例子展示了如何处理对象和字典的情况,那么函数呢?同样的事情,但我们使用双 asterisks 关键字参数:
def my_function(**kwargs):
try:
value = kwargs['some_key']
if value is None:
# do something because 'some_key' is explicitly
# set to None
except KeyError:
# we assign the default
value = None
# and since it's not coming from the caller.
log_something('did not receive "some_key"')
None
仅用作有效值如果您发现代码中充满了上述try/except
模式,只是为了区分None
flags 和None
data,那么只需使用另一个测试值即可。有一种模式,其中超出有效值集的值作为数据结构中的一部分插入,用于控制和测试特殊条件(例如边界,状态等)。这样的值称为哨兵 ,可以使用None
作为信号的方式。在 Python 中创建一个哨兵是微不足道的。
undefined = object()
上面的undefined
对象是唯一的,并且不会对程序可能感兴趣的任何内容做很多事情,因此它是None
作为标志的绝佳替代品。一些警告适用,更多关于代码之后的注意事项。
有功能
def my_function(value, param1=undefined, param2=undefined):
if param1 is undefined:
# we know nothing was passed to it, not even None
log_something('param1 was missing')
param1 = None
if param2 is undefined:
# we got nothing here either
log_something('param2 was missing')
param2 = None
用 dict
value = some_dict.get('some_key', undefined)
if value is None:
log_something("'some_key' was set to None")
if value is undefined:
# we know that the dict didn't have 'some_key'
log_something("'some_key' was not set at all")
value = None
有了一个对象
value = getattr(obj, 'some_attribute', undefined)
if value is None:
log_something("'obj.some_attribute' was set to None")
if value is undefined:
# we know that there's no obj.some_attribute
log_something("no 'some_attribute' set on obj")
value = None
正如我之前提到的,定制哨兵有一些警告。首先,它们不是像None
这样的关键字,所以 python 不保护它们。您可以随时在其定义的模块中覆盖undefined
上述undefined
,因此请小心如何公开和使用它们。接下来, object()
返回的实例不是单例,如果您进行 10 次调用,则会得到 10 个不同的对象。最后,使用哨兵是非常特殊的。哨兵特定于其使用的库,因此其范围通常应限于图书馆的内部。它不应该 “泄漏” 出来。如果外部代码的目的是扩展或补充库的 API,那么外部代码应该只知道它。