Python中的空对象

如何在Python中引用空对象

2146638 次浏览

在Python中,“null”对象是单例None

要检查某物是否为None,请使用#1标识运算符:

if foo is None:...

它不像其他语言那样被称为null,而是#0。这个对象总是只有一个实例,所以如果你愿意,你可以检查与x is None(身份比较)而不是x == None的等价性。

在Python中,要表示没有值,您可以使用值(类型)表示对象,使用""(或len()==0)表示字符串。因此:

if yourObject is None:  # if yourObject == None:...
if yourString == "":  # if yourString.len() == 0:...

关于“==”和“is”之间的区别,使用“==”测试对象身份应该就足够了。然而,由于操作“is”被定义为对象身份操作,使用它可能更正确,而不是 "==". 不确定是否有速度差异。

不管怎样,你可以看看:

根据真值检验,“无”直接测试为FALSE,因此最简单的表达式就足够了:

if not foo:

None,Python的空?

如前所述,测试某物是否被赋予None作为值的最准确方法是使用is身份运算符,它测试两个变量是否指向同一个对象。

>>> foo is NoneTrue>>> foo = 'bar'>>> foo is NoneFalse

基础知识

有且只能有一个None

None是类NoneType的唯一实例,任何进一步实例化该类的尝试都将返回相同的对象,这使得None成为单例。Python新手经常看到提到NoneType的错误消息,并想知道它是什么。我个人认为,这些消息可以简单地通过名称提到None,因为我们很快就会看到,None几乎没有歧义的空间。所以如果你看到一些TypeError消息提到NoneType不能这样做或不能那样做,只要知道它只是None被使用的方式它不能。

此外,None是一个内置常量。一旦您启动Python,它就可以从任何地方使用,无论是在模块、类还是函数中。相比之下,NoneType不是,您需要首先通过查询None的类来获取对它的引用。

>>> NoneTypeNameError: 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运算符

在编写代码时,您可能会像这样测试无意义

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

但它也适用于空字符串

>>> empty==''True

然而

>>> ''==NoneFalse>>> empty is NoneFalse

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

以下两个测试

if value:# Do something
if not value:# Do something

实际上被评估为

if bool(value):# Do something
if not bool(value):# Do something

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

>>> bool(None)False>>> not NoneTrue
>>> bool([])False>>> not []True
>>> class MyFalsey(object):...     def __bool__(self):...         return False>>> f = MyFalsey()>>> bool(f)False>>> not fTrue

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

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 NoneTrue

如果您尝试使用下标符号访问它,将引发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)返回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 hereif value is None:# Do something here because the attribute was set to Noneexcept AttributeError:# We're now handling 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)

同样的,DOS:

try:value = some_dict['some_key']if value is None:# Do something here because 'some_key' is set to Noneexcept KeyError:# Set a defaultvalue = None# And do something because 'some_key' was missing# from the dict.log_something(some_dict)

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

def my_function(**kwargs):try:value = kwargs['some_key']if value is None:# Do something because 'some_key' is explicitly# set to Noneexcept KeyError:# We assign the defaultvalue = 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作为标志的绝佳替代品。

与功能

def my_function(value, param1=undefined, param2=undefined):if param1 is undefined:# We know nothing was passed to it, not even Nonelog_something('param1 was missing')param1 = None

if param2 is undefined:# We got nothing here eitherlog_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_attributelog_something("no 'some_attribute' set on obj")value = None

正如我之前提到的,自定义哨兵有一些注意事项。首先,它们不是像None这样的关键字,所以Python不会保护它们。你可以随时覆盖上面的undefined,在它定义的模块中的任何地方,所以要小心如何公开和使用它们。接下来,object()返回的实例不是单例。如果你进行10次那个调用,你会得到10个不同的对象。最后,哨兵的使用是非常特殊的。哨兵特定于它所使用的库,因此它的范围通常应该限于库的内部。它不应该“泄漏”出去。外部代码只有在其目的是扩展或补充库的API时才应该知道它。

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

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

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

>>>variable = None>>>variable is NoneTrue

更多信息可在python文档

使用f字符串来解决这个问题。

year=Noneyear_val= 'null' if year is None else  str(year)print(f'{year_val}')
null

上面的答案只会对None产生True,但是有float('nan')这样的东西。你可以使用熊猫isnull

>>> import pandas as pd>>> pd.isnull(None)True>>> pd.isnull(float('nan'))True>>> pd.isnull('abc')False>>>

如果没有pandas

>>> a = float('nan')>>> (a != a) or (a == None)True>>> a = None>>> (a != a) or (a == None)True>>>

这之所以有效,是因为float('nan') != float('nan')

>>> float('nan') == float('nan')False>>> float('nan') != float('nan')True>>>

解决Python中“空”元素的简单函数:

代码:

def is_empty(element) -> bool:"""Function to check if input `element` is empty.
Other than some special exclusions and inclusions,this function returns boolean result of Falsy check."""if (isinstance(element, int) or isinstance(element, float)) and element == 0:# Exclude 0 and 0.0 from the Falsy set.return Falseelif isinstance(element, str) and len(element.strip()) == 0:# Include string with one or more empty space(s) into Falsy set.return Trueelif isinstance(element, bool):# Exclude False from the Falsy set.return Falseelse:# Falsy check.return False if element else True

测试:

print("Is empty?\n")print('"" -> ', is_empty(""))print('"      " -> ', is_empty("      "))print('"A" -> ', is_empty("A"))print('"a" -> ', is_empty("a"))print('"0" -> ', is_empty("0"))print("0 -> ", is_empty(0))print("0.0 -> ", is_empty(0.0))print("[] -> ", is_empty([]))print("{} -> ", is_empty({}))print("() -> ", is_empty(()))print("[1, 2] -> ", is_empty([1, 2]))print("(3, 5) -> ", is_empty((3, 5)))print('{"a": 1} -> ', is_empty({"a": 1}))print("None -> ", is_empty(None))print("True -> ", is_empty(True))print("False -> ", is_empty(False))print("NaN -> ", is_empty(float("nan")))print("range(0) -> ", is_empty(range(0)))

输出:

Is empty?
"" ->  True"      " ->  True"A" ->  False"a" ->  False"0" ->  False0 ->  False0.0 ->  False[] ->  True{} ->  True() ->  True[1, 2] ->  False(3, 5) ->  False{"a": 1} ->  FalseNone ->  TrueTrue ->  FalseFalse ->  FalseNaN ->  Falserange(0) ->  True