Python中的空对象?


Answers:


1626

在Python中,“空”对象是singleton None

检查事物是否为“无”的最好方法是使用身份运算符is

if foo is None:
    ...

125
而对于选择的原因egg is Noneegg == None:后者可以被重载,并有可能比较无有效对象时打破(取决于它是如何实现的,但你不要指望每个人都采取comparisions与无虑,你呢?) ,而is总是一样。

94
为什么python设计师不选择“ null”。只是必须与众不同吧!;)
Vidar

35
@Vidar'None'不缺少对象(因为'null'是空引用),它是实际对象。对于任何类型的对象(“ NoneType”除外),您都不会传递“ None”对象。它也不是语言概念。它不是Python内置的语言,它是Python标准库的一部分。无!==(
糟糕

11
@ naught101这没有用;因为没有指针的概念。如果您正在使用ctypes库,则None将用作地址零的同义词,但是仍然没有“空引用”的语言概念。在Python中,即使该对象为None,也总是保留引用该对象。我怀疑这会大大简化语言。
Rushyo 2014年

5
精彩的演讲,解释了“十亿美元的错误”,即无效ref:infoq.com/presentations/…。其他选项(而不是null)是选项或Maybe(自定义)类型。
Michael Trouw 2015年

133

None,Python是否为空?

nullPython中没有,而是None。如前所述,测试是否已将某些None值作为值给出的最准确方法是使用is标识运算符,该运算符用于测试两个变量是否引用同一对象。

>>> 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

您可以None使用Python的identity函数检查其唯一性id()。它返回分配给一个对象的唯一编号,每个对象都有一个。如果两个变量的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

在编写代码时,您可能会想像这样来测试None

if value==None:
    pass

或者像这样测试虚假

if not value:
    pass

您需要了解其含义,以及为什么要明确地说明它通常是一个好主意。

情况1:测试值是否为 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

情况2: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本身之外,该属性还由空列表,元组,集合,字典,字符串以及0以及实现__bool__()magic方法的类中的所有对象共享来共享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()

在上面,您是要init_value()在将值专门设置为时调用None,还是要将值设置为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则会引发a

>>> 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当它不被视为有效值,而更像是执行某些特殊操作的信号时,上面描述的apply 用法。但是,在某些情况下,有时重要的是知道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)

上面的两个示例显示了如何处理对象和字典的情况,函数呢?同样,但为此我们使用了double 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标志和None数据,则只需使用另一个测试值即可。有一种模式是,将超出有效值集的值作为数据的一部分插入数据结构中,并用于控制和测试特殊条件(例如边界,状态等)。这样的值称为哨兵,可以将其用作None信号。在Python中创建一个哨兵很简单。

undefined = object()

undefined上面的对象是唯一的,并且不执行任何程序可能感兴趣的任何事情,因此,它是None作为flag 的绝佳替代品。一些注意事项适用,有关代码之后的更多说明。

具有功能

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

与字典

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随时在定义的模块中的任何位置覆盖上面的内容,因此请谨慎使用它们。接下来,by返回的实例object()不是单例,如果您进行10次该调用,则会得到10个不同的对象。最后,哨兵的使用是高度特质的。前哨特定于它所使用的库,因此,其范围通常应限于库的内部。它不应该“泄漏”出去。仅当外部代码的目的是扩展或补充库的API时,外部代码才应意识到这一点。


关于什么:无==东西?
hkBst

@hkBst我猜你的问题是关于python如何评估相等性。看看这个stackoverflow.com/questions/3588776/...
迈克尔Ekoka

嗯,所以IIUC通常仍然会最终打电话给事物。在这种情况下,我撤回了我的建议。
hkBst

@MichaelEkoka您可以共享此令人印象深刻且有用的信息的来源。
Anidhya Bhatnagar

标准做法。通过Python教程可以找到一些提示,但是阅读流行项目的源代码是我的第一条建议,它可以让您快速沉浸于惯用的Python中
Michael Ekoka,

67

它不像其他语言那样称为null,而是None。此对象始终只有一个实例,因此您可以根据需要使用x is None(同一性比较)而不是来检查是否相等x == None


25
我将找到一种通过重新实例化来破坏Python的方法None。然后,所有NoneType与之作比较的聪明人都会胜利!
Zenexer

28

在Python中,要表示缺少值,可以对对象使用None值(types.NoneType.None),对字符串使用“”(或len()== 0)。因此:

if yourObject is None:  # if yourObject == None:
    ...

if yourString == "":  # if yourString.len() == 0:
    ...

关于“ ==”和“ is”之间的区别,使用“ ==”测试对象身份就足够了。但是,由于将“ is”操作定义为对象标识操作,因此使用它而不是“ ==”可能更正确。不知道是否存在速度差异。

无论如何,您可以看一下:


8
据我所知,(0 == false)在每种编程语言中都返回true。这是因为false编码为0,而true编码为所有非0的值。但是,请不要使“ is”运算符与“ ==”不同。在Java中,“ ==”和“等于”之间几乎相同。实际上,运算符“是”将检查两个对象是否相同(相同的实例,而不是相同的内容)!
Paolo Rovelli 2013年

12
Pay,FYI,(0 == false)并非在每种编程语言中都返回true。一个快速的计数器示例是Scala,其中(0 == false)返回false,并且我确信Scala不是将数字与布尔值进行比较时唯一返回false的编程语言。
罗伯·威尔顿

2
好的,我知道了!然后,用大多数编程语言说。
Paolo Rovelli 2014年

3
在JavaScript中,0 == false返回的原因true是因为double-equals运算符确实键入了强制。但是,使用三等号运算符0 === false将返回false,因为'number'和'boolean'是不同的类型。
jkdev

1
@PaoloRovelli,在Lua,Ruby和Clojure中,0被视为true条件句。在Rust和Go中,0并且false 是无法比较相等性的不同类型。
踏板车

0

Null是一种特殊的对象类型,例如:

>>>type(None)
<class 'NoneType'>

您可以检查对象是否在类“ NoneType”中:

>>>variable = None
>>>variable is None
True

有关更多信息,请参见Python Docs。


-1

Per Truth值测试,“ None”直接测试为FALSE,因此最简单的表达式就足够了:

if not foo:

3
不,不会。这表达式将返回True任何 falsy价值,而不仅仅是None
insert_name_here

是的,简单的“ if not foo:”将无法正确回答原始问题,如前所述。但是,python是动态类型的,并邀请其减少语法协议,因此,对我来说,考虑更简单,相似的结构似乎很有效。
artejera
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.