python中的空对象null object?

null object in Python?

如何在Python中引用空对象?


在python中,"null"对象是singleton None

检查事物是否"不存在"的最佳方法是使用身份操作符is

1
2
if foo is None:
    ...


None,python是空的?

python中没有null,而是None。如前所述,测试某个给定None作为值的最准确方法是使用is标识操作符,该操作符测试两个变量引用同一对象。好的。

1
2
3
4
5
>>> 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的类来获取对它的引用。好的。

1
2
3
4
>>> NoneType
NameError: name 'NoneType' is not defined
>>> type(None)
NoneType

您可以使用python的标识函数id()检查None的唯一性。它返回分配给一个对象的唯一编号,每个对象都有一个。如果两个变量的ID相同,那么它们实际上指向同一个对象。好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> 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,但不再如此。甚至不作为类属性或函数的限制。好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 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运算符

在编写代码时,您可能会尝试测试这样的不存在性:好的。

1
2
if value==None:
    pass

或者像这样测试错误好的。

1
2
if not value:
    pass

你需要理解其中的含义以及为什么直截了当往往是个好主意。好的。案例1:测试值是否为None

为什么这样做好的。

1
value is None

而不是好的。

1
value==None

第一个相当于:好的。

1
id(value)==id(None)

value==None的表达实际上是这样应用的。好的。

1
value.__eq__(None)

如果值真的是None,那么您将得到预期的结果。好的。

1
2
3
>>> nothing = function_that_does_nothing()
>>> nothing.__eq__(None)
True

在大多数常见的情况下,结果都是一样的,但是__eq__()方法打开了一扇门,这会使任何精度保证无效,因为它可以在类中被重写以提供特殊的行为。好的。

考虑这个类。好的。

1
2
3
>>> class Empty(object):
...     def __eq__(self, other):
...         return not other

所以你在None上试试,就行了。好的。

1
2
3
>>> empty = Empty()
>>> empty==None
True

但它也适用于空字符串好的。

1
2
>>> empty==''
True

然而好的。

1
2
3
4
>>> ''==None
False
>>> empty is None
False

案例2:使用None作为布尔值

以下两个测试好的。

1
2
3
4
5
if value:
    # do something

if not value:
    # do something

实际评估为好的。

1
2
3
4
5
if bool(value):
    # do something

if not bool(value):
    # do something

None是一个"假",即如果强制转换为布尔值,它将返回False,如果应用not运算符,它将返回True。但是请注意,它不是None的独有属性。除了False本身之外,该属性还由空列表、元组、集合、dict、字符串以及0以及实现__bool__()magic方法以返回False的类中的所有对象共享。好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
>>> 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

因此,当以以下方式测试变量时,要特别注意测试中包含或排除的内容:好的。

1
2
3
def some_function(value=None):
    if not value:
        value = init_value()

在上面,您是指当值专门设置为None时调用init_value(),还是说设置为0的值、空字符串或空列表也应该触发初始化。就像我说的,要留心。因为在Python中,显式通常比隐式好。好的。实践中的NoneNone用作信号值

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

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

1
2
3
def my_function(value, param=None):
    if param is None:
        # do something outrageous!

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

1
2
3
value = getattr(some_obj, 'some_attribute', None)
if value is None:
    # do something spectacular!

默认情况下,当试图访问不存在的密钥时,字典的get()方法返回None:好的。

1
2
3
4
>>> some_dict = {}
>>> value = some_dict.get('foo')
>>> value is None
True

如果您试图使用下标符号访问它,那么会引发KeyError。好的。

1
2
>>> value = some_dict['foo']
KeyError: 'foo'

同样,如果尝试弹出一个不存在的项好的。

1
2
>>> value = some_dict.pop('foo')
KeyError: 'foo'

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

1
2
3
value = some_dict.pop('foo', None)
if value is None:
    # booom!

None同时用作标志和有效值

上述None的用法适用于不被认为是有效值,但更像是做特殊事情的信号的情况。然而,有些情况下,有时需要知道None的来源,因为即使它被用作信号,它也可能是数据的一部分。好的。

当使用getattr(some_obj, 'attribute_name', None)返回None查询对象的属性时,不会告诉您试图访问的属性是设置为None还是完全不在对象中。同样的情况下,从像some_dict.get('some_key')这样的字典访问密钥时,您不知道some_dict['some_key']是否丢失,或者它是否刚刚设置为None。如果需要这些信息,通常的处理方法是直接尝试从try/except构造中访问属性或键:好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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类似:好的。

1
2
3
4
5
6
7
8
9
10
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)

上面的两个例子说明了如何处理对象和字典的情况,函数呢?同样的,但是我们使用了双星号关键字参数:好的。

1
2
3
4
5
6
7
8
9
10
11
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数据,那么只需使用另一个测试值。有一种模式,即在数据结构中插入一个超出有效值集的值作为数据的一部分,用于控制和测试特殊条件(如边界、状态等)。这种值被称为sentinel,可以像使用None作为信号一样使用。在Python中创建一个哨兵是很简单的。好的。

1
undefined = object()

上面的undefined对象是唯一的,它不做任何可能对程序感兴趣的事情,因此它是None作为标志的一个很好的替代品。一些注意事项适用,更多的是在代码之后。好的。

具有功能好的。

1
2
3
4
5
6
7
8
9
10
11
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好的。

1
2
3
4
5
6
7
8
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

带有对象好的。

1
2
3
4
5
6
7
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,因此请注意如何公开和使用它们。接下来,object()返回的实例不是单例实例,如果调用10次,就会得到10个不同的对象。最后,哨兵的使用是非常特殊的。Sentinel是特定于它所使用的库的,因此它的范围通常应限于库的内部。它不应该"泄露"出去。只有当外部代码的目的是扩展或补充库的API时,它们才应该意识到这一点。好的。好啊。


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


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

1
2
3
4
5
if yourObject is None:  # if yourObject == None:
    ...

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

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

不管怎样,你可以看看:

  • python内置常量文档页。
  • python真值测试文档页。


根据真值测试,"无"直接测试为假,因此最简单的表达式将满足:

1
if not foo: