Python中的null对象?

Liz*_*ard 1097 python null

我如何在Python中引用null对象?

Ben*_*mes 1486

在Python中,'null'对象是单例None.

检查"Noneness"的最佳方法是使用identity运算符is:

if foo is None:
    ...
Run Code Online (Sandbox Code Playgroud)

  • 选择`egg的原因是'无'而不是'egg == None`:后者可以重载,并且在将有效对象与None进行比较时可能会中断(取决于它是如何实现的,但你不希望每个人都这样做)考虑到与None的比较,是吗?),而`is`总是起作用. (119认同)
  • 为什么python设计师只选择"null".只是必须是不同的不是你!;) (87认同)
  • @Vidar'None'不是缺少对象(因为'null'是一个空引用),它是一个实际的对象.你永远不会得到一个'None'对象传递一个除'NoneType'以外的任何类型的对象.它也不是一种语言概念..它不是Python内置的语言,它是Python标准库的一部分.没有!==(哼)无效 (31认同)
  • @ naught101这没有任何意义; 因为没有指针的概念.如果您使用的是ctypes库,则None将用作地址零的同义词,但仍然没有"null引用"的语言概念.在Python中,您始终会引用某种对象,即使该对象为None.我怀疑这大大简化了语言. (10认同)
  • 伟大的演示文稿解释了"十亿美元的错误",这是一个空的参考:http://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare.其他选项而不是null是Options或Maybe(自定义)类型. (4认同)
  • 而且为了完整性,这是"如果foo不是None:". (3认同)

Mic*_*oka 103

None,Python的null?

null在Python中没有,而是有None.如前所述,测试某些东西None作为值的最准确方法是使用isidentity运算符,该运算符测试两个变量引用同一个对象.

>>> foo is None
True
>>> foo = 'bar' 
>>> foo is None
False
Run Code Online (Sandbox Code Playgroud)

基础

有,只能是一个 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
Run Code Online (Sandbox Code Playgroud)

您可以None使用Python的身份功能检查其唯一性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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

因此可以安全地假设所有None参考都是相同的.没有"习惯" None.

测试None使用is操作员

在编写代码时,您可能会尝试像这样测试Noneness:

if value==None:
    pass
Run Code Online (Sandbox Code Playgroud)

或者像这样测试虚假

if not value:
    pass
Run Code Online (Sandbox Code Playgroud)

您需要了解其含义以及为什么明确这一点通常是一个好主意.

案例1:测试值是否为 None

为什么这样做

value is None
Run Code Online (Sandbox Code Playgroud)

而不是

value==None
Run Code Online (Sandbox Code Playgroud)

第一个相当于:

id(value)==id(None)
Run Code Online (Sandbox Code Playgroud)

而表达式value==None实际上是这样应用的

value.__eq__(None)
Run Code Online (Sandbox Code Playgroud)

如果价值真的是None那么你会得到你所期望的.

>>> nothing = function_that_does_nothing()
>>> nothing.__eq__(None)
True
Run Code Online (Sandbox Code Playgroud)

在大多数常见情况下,结果将是相同的,但是该__eq__()方法打开了一扇门,无法保证准确性,因为它可以在类中被覆盖以提供特殊行为.

考虑这个课程.

>>> class Empty(object):
...     def __eq__(self, other):
...         return not other
Run Code Online (Sandbox Code Playgroud)

所以你试试它None,它的工作原理

>>> empty = Empty()
>>> empty==None
True
Run Code Online (Sandbox Code Playgroud)

但是它也适用于空字符串

>>> empty==''
True
Run Code Online (Sandbox Code Playgroud)

但是

>>> ''==None
False
>>> empty is None
False
Run Code Online (Sandbox Code Playgroud)

案例2:None用作布尔值

以下两个测试

if value:
    # do something

if not value:
    # do something
Run Code Online (Sandbox Code Playgroud)

实际上被评估为

if bool(value):
    # do something

if not bool(value):
    # do something
Run Code Online (Sandbox Code Playgroud)

None是一个"假",意味着如果强制转换为布尔值,它将返回False,如果应用not操作符,它将返回True.但请注意,它不是唯一的属性None.除了False它自身之外,属性由空列表,元组,集合,dicts,字符串以及0以及实现__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
Run Code Online (Sandbox Code Playgroud)

因此,当以下列方式测试变量时,请特别注意您在测试中包含或排除的内容:

def some_function(value=None):
    if not value:
        value = init_value()
Run Code Online (Sandbox Code Playgroud)

在上面,你是指在init_value()专门设置值时调用None,还是意味着设置为的值0,空字符串或空列表也应该触发初始化.就像我说的那样,要小心.因为Python中的情况通常比隐式更好.

None 在实践中

None 用作信号值

None在Python中具有特殊的地位.它是最受欢迎的基准值,因为许多算法将其视为特殊值.在这种情况下,它可以用作标志,表示条件需要一些特殊处理(例如设置默认值).

您可以分配None函数的关键字参数,然后显式测试它.

def my_function(value, param=None):
    if param is None:
        # do something outrageous!
Run Code Online (Sandbox Code Playgroud)

您可以在尝试获取对象的属性时将其作为默认值返回,然后在执行特殊操作之前显式测试它.

value = getattr(some_obj, 'some_attribute', None)
if value is None:
    # do something spectacular!
Run Code Online (Sandbox Code Playgroud)

默认情况下,字典的get()方法None在尝试访问不存在的键时返回:

>>> some_dict = {}
>>> value = some_dict.get('foo')
>>> value is None
True
Run Code Online (Sandbox Code Playgroud)

如果您尝试使用下标符号来访问它,KeyError则会引发

>>> value = some_dict['foo']
KeyError: 'foo'
Run Code Online (Sandbox Code Playgroud)

同样,如果您尝试弹出不存在的项目

>>> value = some_dict.pop('foo')
KeyError: 'foo'
Run Code Online (Sandbox Code Playgroud)

您可以使用通常设置为的默认值来抑制 None

value = some_dict.pop('foo', None)
if value is None:
    # booom!
Run Code Online (Sandbox Code Playgroud)

None 用作标志和有效值

应用的上述用途,None当它不被认为是有效值时,更像是做某些特殊事物的信号.然而,在某些情况下,有时候知道从何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)
Run Code Online (Sandbox Code Playgroud)

与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)
Run Code Online (Sandbox Code Playgroud)

以上两个例子展示了如何处理对象和字典的情况,那么函数呢?同样的事情,但我们使用双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"')
Run Code Online (Sandbox Code Playgroud)

None 仅用作有效值

如果您发现您的代码充满了上述try/except模式,只是为了区分None标志和None数据,那么只需使用另一个测试值.有一种模式,其中超出有效值集的值作为数据结构中的一部分插入,用于控制和测试特殊条件(例如边界,状态等).这样的值称为哨兵,它可以用作None信号的方式.在Python中创建一个哨兵是微不足道的.

undefined = object()
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

用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
Run Code Online (Sandbox Code Playgroud)

有了一个对象

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
Run Code Online (Sandbox Code Playgroud)

正如我之前提到的,定制哨兵有一些警告.首先,它们不是关键字None,因此python不保护它们.您可以undefined随时,在其定义的模块中的任何位置覆盖您的上述内容,因此请务必小心如何公开和使用它们.接下来,返回的实例object()不是单例,如果您进行10次调用,则会获得10个不同的对象.最后,使用哨兵是非常特殊的.哨兵特定于其使用的库,因此其范围通常应限于图书馆的内部.它不应该"泄漏"出来.如果外部代码的目的是扩展或补充库的API,那么外部代码应该只知道它.


And*_*Dog 64

它不像其他语言那样被称为null,但是None.此对象始终只有一个实例,因此您可以检查是否与x is None(身份比较)等效,而不是(x == None如果需要).

  • 我将通过重新实例化"无"来找到破解Python的方法.那么所有那些与"NoneType"相比较的聪明人都会胜利! (24认同)

Pao*_*lli 28

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

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

if yourString == "":  # if yourString.len() == 0:
    ...
Run Code Online (Sandbox Code Playgroud)

关于"=="和"is"之间的区别,使用"=="测试对象标识应该足够了.但是,由于操作"is"被定义为对象标识操作,因此使用它可能更正确,而不是"==".不确定是否有速度差异.

无论如何,你可以看看:

  • Paolo,FYI,(0 == false)在每种编程语言中都不会返回true.一个快速计数器示例是Scala,其中(0 == false)返回false,并且我确信Scala不是唯一一种在将数字与布尔值进行比较时返回false的编程语言. (12认同)
  • 据我所知,(0 == false)在每种编程语言中都返回true.这是因为false被编码为0而"true"被编码为非0.但是,请注意,"is"运算符与"=="运算符不同.这与Java中"=="和"equals"之间的差异大致相同.实际上,运营商"是"检查两个对象是否相同(相同的实例而不是相同的内容)! (8认同)
  • 在JavaScript中,'0 == false`返回'true`的原因是因为double-equals运算符确实输入了强制类型.但是,对于三重等于运算符,"0 === false"返回"false",因为"number"和"boolean"是不同的类型. (3认同)
  • 好的,我知道了!然后,让我们说在大多数编程语言中. (2认同)

U10*_*ard 6

上面的答案只会导致TrueNone但有这样的事情float('nan')。你可以使用 pandas isnull

>>> import pandas as pd
>>> pd.isnull(None)
True
>>> pd.isnull(float('nan'))
True
>>> pd.isnull('abc')
False
>>> 
Run Code Online (Sandbox Code Playgroud)

或者没有pandas

>>> a = float('nan')
>>> (a != a) or (a == None)
True
>>> a = None
>>> (a != a) or (a == None)
True
>>> 
Run Code Online (Sandbox Code Playgroud)

这样做的原因是float('nan') != float('nan')

>>> float('nan') == float('nan')
False
>>> float('nan') != float('nan')
True
>>> 
Run Code Online (Sandbox Code Playgroud)