Python中的空对象?

问题:Python中的空对象?

如何在Python中引用null对象?

How do I refer to the null object in Python?


回答 0

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

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

if foo is None:
    ...

In Python, the ‘null’ object is the singleton None.

The best way to check things for “Noneness” is to use the identity operator, is:

if foo is None:
    ...

回答 1

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时,外部代码才应意识到这一点。

None, Python’s null?

There’s no null in Python, instead there’s None. As stated already the most accurate way to test that something has been given None as a value is to use the is identity operator, which tests that two variables refer to the same object.

>>> foo is None
True
>>> foo = 'bar' 
>>> foo is None
False

The basics

There is and can only be one None

None is the sole instance of the class NoneType and any further attempts at instantiating that class will return the same object, which makes None a singleton. Newcomers to Python often see error messages that mention NoneType and wonder what it is. It’s my personal opinion that these messages could simply just mention None by name because, as we’ll see shortly, None leaves little room to ambiguity. So if you see some TypeError message that mentions that NoneType can’t do this or can’t do that, just know that it’s simply the one None that was being used in a way that it can’t.

Also, None is a built-in constant, as soon as you start Python it’s available to use from everywhere, whether in module, class, or function. NoneType by contrast is not, you’d need to get a reference to it first by querying None for its class.

>>> NoneType
NameError: name 'NoneType' is not defined
>>> type(None)
NoneType

You can check None‘s uniqueness with Python’s identity function id(). It returns the unique number assigned to an object, each object has one. If the id of two variables is the same, then they point in fact to the same object.

>>> 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 cannot be overwritten

In much older version of Python (before 2.4) it was possible to reassign None, but not anymore. Not even as a class attribute or in the confines of a function.

# 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

It’s therefore safe to assume that all None references are the same. There’s no “custom” None.

To test for None use the is operator

When writing code you might be tempted to test for Noneness like this:

if value==None:
    pass

Or to test for falsehood like this

if not value:
    pass

You need to understand the implications and why it’s often a good idea to be explicit.

Case 1: testing if a value is None

why do this

value is None

rather than

value==None

The first is equivalent to:

id(value)==id(None)

Whereas the expression value==None is in fact applied like this

value.__eq__(None)

if the value really is None then you’ll get what you expected.

>>> nothing = function_that_does_nothing()
>>> nothing.__eq__(None)
True

In most common cases the outcome will be the same, but the __eq__() method opens a door that voids any guarantee of accuracy, since it can be overridden in a class to provide special behavior.

Consider this class.

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

So you try it on None and it works

>>> empty = Empty()
>>> empty==None
True

But then it also works on the empty string

>>> empty==''
True

And yet

>>> ''==None
False
>>> empty is None
False

Case 2: Using None as a boolean

The following two tests

if value:
    # do something

if not value:
    # do something

are in fact evaluated as

if bool(value):
    # do something

if not bool(value):
    # do something

None is a “falsey”, meaning that if cast to a boolean it will return False and if applied the not operator it will return True. Note however that it’s not a property unique to None. In addition to False itself, the property is shared by empty lists, tuples, sets, dicts, strings, as well as 0, and all objects from classes that implement the __bool__() magic method to return 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

So when testing for variables in the following way, be extra aware of what you’re including or excluding from the test:

def some_function(value=None):
    if not value:
        value = init_value()

In the above, did you mean to call init_value() when the value is set specifically to None, or did you mean that a value set to 0, or the empty string, or an empty list should also trigger the initialization. Like I said, be mindful. As it’s often the case in Python explicit is better than implicit.

None in practice

None used as a signal value

None has a special status in Python. It’s a favorite baseline value because many algorithms treat it as an exceptional value. In such scenarios it can be used as a flag to signal that a condition requires some special handling (such as the setting of a default value).

You can assign None to the keyword arguments of a function and then explicitly test for it.

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

You can return it as the default when trying to get to an object’s attribute and then explicitly test for it before doing something special.

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

By default a dictionary’s get() method returns None when trying to access a non-existing key:

>>> some_dict = {}
>>> value = some_dict.get('foo')
>>> value is None
True

If you were to try to access it by using the subscript notation a KeyError would be raised

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

Likewise if you attempt to pop a non-existing item

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

which you can suppress with a default value that is usually set to None

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

None used as both a flag and valid value

The above described uses of None apply when it is not considered a valid value, but more like a signal to do something special. There are situations however where it sometimes matters to know where None came from because even though it’s used as a signal it could also be part of the data.

When you query an object for its attribute with getattr(some_obj, 'attribute_name', None) getting back None doesn’t tell you if the attribute you were trying to access was set to None or if it was altogether absent from the object. Same situation when accessing a key from a dictionary like some_dict.get('some_key'), you don’t know if some_dict['some_key'] is missing or if it’s just set to None. If you need that information, the usual way to handle this is to directly attempt accessing the attribute or key from within a try/except construct:

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)

Similarly with 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)

The above two examples show how to handle object and dictionary cases, what about functions? Same thing, but we use the double asterisks keyword argument to that end:

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 used only as a valid value

If you find that your code is littered with the above try/except pattern simply to differentiate between None flags and None data, then just use another test value. There’s a pattern where a value that falls outside the set of valid values is inserted as part of the data in a data structure and is used to control and test special conditions (e.g. boundaries, state, etc). Such a value is called a sentinel and it can be used the way None is used as a signal. It’s trivial to create a sentinel in Python.

undefined = object()

The undefined object above is unique and doesn’t do much of anything that might be of interest to a program, it’s thus an excellent replacement for None as a flag. Some caveats apply, more about that after the code.

With function

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

With 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

With an object

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

As I mentioned earlier custom sentinels come with some caveats. First, they’re not keywords like None, so python doesn’t protect them. You can overwrite your undefined above at any time, anywhere in the module it’s defined, so be careful how you expose and use them. Next, the instance returned by object() is not a singleton, if you make that call 10 times you get 10 different objects. Finally, usage of a sentinel is highly idiosyncratic. A sentinel is specific to the library it’s used in and as such its scope should generally be limited to the library’s internals. It shouldn’t “leak” out. External code should only become aware of it, if their purpose is to extend or supplement the library’s API.


回答 2

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

It’s not called null as in other languages, but None. There is always only one instance of this object, so you can check for equivalence with x is None (identity comparison) instead of x == None, if you want.


回答 3

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

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

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

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

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

In Python, to represent the absence of a value, you can use the None value (types.NoneType.None) for objects and “” (or len() == 0) for strings. Therefore:

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

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

Regarding the difference between “==” and “is”, testing for object identity using “==” should be sufficient. However, since the operation “is” is defined as the object identity operation, it is probably more correct to use it, rather than “==”. Not sure if there is even a speed difference.

Anyway, you can have a look at:


回答 4

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

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

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

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

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

Null is a special object type like:

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

You can check if an object is in class ‘NoneType’:

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

More information is available at Python Docs


回答 5

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

if not foo:

Per Truth value testing, ‘None’ directly tests as FALSE, so the simplest expression will suffice:

if not foo: