跳转到主要内容

空值和哨兵,如(但不限于)None、False和True

项目描述

travisci PyPI Package latest release Supported versions Supported implementations Wheel packaging support Test line coverage Test branch coverage

帮助定义与Python内置值(如NoneFalseTrue)平行但不同的“空”值和哨兵。

None 是一个很好的 哨兵值,也是 空对象模式 的经典实现。

但有时你需要多个“空”值来表示空的不同方面。“什么都没有”在逻辑上与“未定义”、“禁止”、“数据结束”和其他类型的“空”不同。

nulltype 帮助您以不超载 None(或 False0{}[]"" 或其他可能的“这里什么也没有!”值)的方式轻松表示空的不同方面。它有助于创建具有特定意义的标识符,例如 PassthroughProhibitedUndefined

如果您需要非 True 的真值哨兵,它也会帮助您做到这一点。并且将以易于消费、现成、全面测试的方式完成。

用法

from nulltype import NullType

Void = NullType('Void')

# following just to show it's working
assert bool(Void) == False
assert len(EmpVoidty) == 0
assert list(Void) == []
assert Void.some_attribute is Empty
assert Void[22] is Nothing
assert Void("hey", 12) is Empty

您可以根据喜好创建任意数量的自定义空值。为了方便起见,已导出几个默认值,EmptyNullNothing。这样,如果您不想创建自己的,可以轻松导入预定义的空值。

from nulltype import Empty

无物之力

在解析数据或遍历可能存在或不存在的数据结构时,可选的空类型特别有用。这在处理如 REST API 返回的数据时很常见。

例如,谷歌 Gmail API 的文档 建议以下代码

threads = gmail_service.users().threads().list(userId='me').execute()
if threads['threads']:
    for thread in threads['threads']:
        print 'Thread ID: %s' % (thread['id'])

这里有很多操作只是为了避免有问题的不定引用。如果您已经定义了 Nothing 空类型,代码会更短(并避免额外的非常短暂的变量)

results = gmail_service.users().threads().list(userId='me').execute()
for thread in results.get('threads', Nothing):
    print 'Thread ID: %s' % (thread['id'])

三行与四行可能看起来不是很大的优势,但随着任务复杂性的增加,其价值会增加。许多这样的“如果它在那里,那么…”结构在处理 API 结果、XML 解析树和其他基本嵌套信息源时都深深嵌套。在每个嵌套级别上节省一个守卫条件会迅速累加。

虽然您几乎可以在标准 Python 中做到这一点,但与 Nothing 不同,None 不可迭代。您可能会使用空列表 [](或等效的全局变量,如 EMPTYLIST)作为 get 方法的替代值。然而,根据许多解析器和 API 的文档,这种用法在当今 Python 社区中并不普遍。EMPTYLIST 方法也仅适用于返回列表的例程,而“尽管去拿吧”的 nulltype 模型对于更长的访问链也很有用。

results.get("payload", Nothing).get("headers", Nothing)

将返回正确的对象,如果没有则返回 Nothing。如果您尝试测试它(例如,使用 if 或逻辑表达式)或遍历它(例如,使用 for),它将表现得像空列表或 False - 什么在特定上下文中最有用。无论您是在迭代、索引、解引用、调用还是以其他方式访问它,NullType 都不会受到影响。

Nothing 不是什么都没有。它是一种将简化您的代码的东西。

通用哨兵和特殊值

虽然 nulltype 经常用于定义新的“空”值类型,但实际上它更通用。除了不同的“空”形式之外,NullType 实例也是良好的通用哨兵或特殊值。而不是旧的

class MySentinelClass(object):
    pass

使用

MySentinel = NullType('MySentinel')

这为您提供了具有已知真值属性和更佳打印表示的值。

>>> print MySentinelClass               # fugly
<class '__main__.MySentinelClass'>

>>> print MySentinel                    # just right
MySentinel

如果需要使用一个真实值(而非假值或空值)作为哨兵值,请使用NonNullType,它是NullType的伴侣,在几乎相同的方式下工作,但评估结果为真。

from nulltype import NonNullType

Full = NonNullType('Full')

assert bool(Full) is True
assert len(Full) == 1
assert list(Full) == [Full]
assert Full.some_attribute is Full
assert Full[22] is Full
assert Full("hey", 12) is Full

经验表明,nullish哨兵通常是足够且更好的选择。即使是NonNullType的“所有内容都折叠到相同的值”特性也赋予它一种某种程度上的null-like或至少是非反应性的性质。但如果你确实需要一个真-like哨兵,这里就有。

独特性

NullType实例旨在是单例,每个程序只有一个。它们几乎是这样的,尽管技术上可以有多个NullType实例,这使得它更像是一个多例模式

目前并没有强制执行每个单例的独特性,这使得它更像是一种使用约定而非严格的法律。即使是最小的关注,这个问题在0%的时间里出现。

注释

  • 已成功打包并针对所有晚期版本的Python进行了测试:2.6、2.7、3.3、3.4、3.5、3.6和3.7预发布版,以及PyPy和PyPy3的最新构建。

  • 查看CHANGES.yml以获取完整的变更日志。

  • 使用pytestpytest-covcoveragetox进行自动多版本测试。使用Travis-CI进行持续集成测试。使用pyroma进行打包代码审查。

  • 类似的模块包括sentinelsnull。在这些模块中,我更喜欢sentinels,因为它显然是为Python 3准备的,包括pickle机制。noattr是一个新的替代品。

  • 要使用空值Empty来简化JSON和其他数据格式的解析,请查看items

  • 作者Jonathan Eunice@jeunice在Twitter上欢迎您的评论和建议。

安装

要安装或升级到最新版本

pip install -U nulltype

您可能需要使用sudo前缀来授权在Unix、Linux和macOS上安装。在没有超级用户权限的环境中,您可能想使用pip的--user选项,仅安装给单个用户,而不是系统范围。在具有多个Python版本的系统上,您可能还需要使用特定的pip3pip2命令,而不是默认的pip。作为备份,将pip作为Python模块运行可以在pip版本作为独立命令表现不佳的复杂情况下拯救您的理智。

python3.6 -m pip install -U nulltype

测试

要运行模块测试,请使用以下命令之一

tox                # normal run - speed optimized
tox -e py27        # run for a specific version only (e.g. py27, py34)
tox -c toxcov.ini  # run full coverage tests

项目详情


下载文件

下载适用于您的平台文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。

源分布

nulltype-2.3.1.zip (20.1 kB 查看哈希值)

上传时间

构建分布

nulltype-2.3.1-py2.py3-none-any.whl (11.1 kB 查看哈希值)

上传时间 Python 2 Python 3