Python 中的空对象

2025-02-20 09:25:00
admin
原创
26
摘要:问题描述:如何在 Python 中引用空对象?解决方案 1:在 Python 中,“null”对象是单例None。要检查某个东西是否为None,请使用is身份运算符:if foo is None: ... 解决方案 2:None,Python的null?Python 中没有null;而是None。如前...

问题描述:

如何在 Python 中引用空对象?


解决方案 1:

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

要检查某个东西是否为None,请使用is身份运算符:

if foo is None:
    ...

解决方案 2:

None,Python的null?

Python 中没有null;而是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 的标识函数检查 的唯一性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运算符

当编写代码时,你可能会想像这样测试Noneness :

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__()魔术方法以返回 的类中的所有对象共享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则会出现

>>> 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用作标志和有效值

上述使用 apply 的情形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 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)

字典也类似:

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)

以上两个示例展示了如何处理对象和字典的情况。函数呢?同样的事情,但我们使用双星号关键字参数来实现这一点:

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标志的绝佳替代品。有一些注意事项,代码后面会详细介绍。

具有功能

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在定义模块的任何时间、任何位置覆盖上述内容,因此请谨慎公开和使用它们。其次,返回的实例object()不是单例。如果您进行 10 次该调用,您将获得 10 个不同的对象。最后,哨兵的使用非常特殊。哨兵特定于它所使用的库,因此其范围通常应限于库的内部。它不应该“泄漏”出去。外部代码只有在其目的是扩展或补充库的 API 时才应该知道它。

解决方案 3:

它不像其他语言那样被称为 null,但是None。此对象始终只有一个实例,因此,如果您愿意,可以使用x is None(身份比较) 而不是来检查等价性。x == None

解决方案 4:

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

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

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

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

无论如何,你可以看看:

  • Python内置常量文档页面。

  • Python真值测试文档页面。

解决方案 5:

上面的答案只会得到TrueNone但还有float('nan')。你可以使用 pandas 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
>>> 

解决方案 6:

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

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

null

解决方案 7:

在 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 False
    elif isinstance(element, str) and len(element.strip()) == 0:
        # Include string with one or more empty space(s) into Falsy set.
        return True
    elif isinstance(element, bool):
        # Exclude False from the Falsy set.
        return False
    else:
        # Falsy check.
        return False if element else True

测试:

print("Is empty?
")
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" ->  False
0 ->  False
0.0 ->  False
[] ->  True
{} ->  True
() ->  True
[1, 2] ->  False
(3, 5) ->  False
{"a": 1} ->  False
None ->  True
True ->  False
False ->  False
NaN ->  False
range(0) ->  True

解决方案 8:

想象一下,如果查询返回变量测试的空值

test if test !=None else 0

解决方案 9:

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

if not foo:

解决方案 10:

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

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

您可以检查某个对象是否属于“NoneType”类:

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

更多信息请参阅Python 文档

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1265  
  IPD(Integrated Product Development)即集成产品开发,是一套先进的、成熟的产品开发管理理念、模式和方法。随着市场竞争的日益激烈,企业对于提升产品开发效率、降低成本、提高产品质量的需求愈发迫切,IPD 项目管理咨询市场也迎来了广阔的发展空间。深入探讨 IPD 项目管理咨询的市场需求与发展,...
IPD集成产品开发流程   17  
  IPD(Integrated Product Development)产品开发流程是一套先进的、被广泛应用的产品开发管理体系,它涵盖了从产品概念产生到产品推向市场并持续优化的全过程。通过将市场、研发、生产、销售等多个环节紧密整合,IPD旨在提高产品开发的效率、质量,降低成本,增强企业的市场竞争力。深入了解IPD产品开发...
IPD流程中TR   21  
  IPD(Integrated Product Development)测试流程是确保产品质量、提升研发效率的关键环节。它贯穿于产品从概念到上市的整个生命周期,对企业的成功至关重要。深入理解IPD测试流程的核心要点,有助于企业优化研发过程,打造更具竞争力的产品。以下将详细阐述IPD测试流程的三大核心要点。测试策略规划测试...
华为IPD   18  
  华为作为全球知名的科技企业,其成功背后的管理体系备受关注。IPD(集成产品开发)流程作为华为核心的产品开发管理模式,在创新管理与技术突破方面发挥了至关重要的作用。深入剖析华为 IPD 流程中的创新管理与技术突破,对于众多企业探索自身发展路径具有重要的借鉴意义。IPD 流程概述IPD 流程是一种先进的产品开发管理理念和方...
TR评审   16  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用