返回

文章详情

Python 的预定义常量有点奇怪

Hacker News2026年8月25日 21:39

Python 有 6 个预定义的 "常量":True、False、None、__debug__、省略号(或等同于 ...)和 NotImplemented。但是它们都以稍微不同的方式表现,这让我有些困惑。True、False 和 None 是关键字,它们不是标识符,它们就是直截了当的词法符号。这真的很奇怪;在 Python 中没有其他东西像这样。通常,内容是在常规名称解析期间解决的,而不是在词法分析器本身中。这个现象的一个有趣副作用是,像 x.True 这样的表达式会引发 SyntaxError。我很好奇做出这个决定的理由是什么(如果有的话)。关于这些常量还有一些更有趣的内容,不过我会稍后再提,因为这与其他常量有联系。__debug__ 是一个布尔常量:它通常为 True,但在使用 -O 运行时,它为 False。这个想法类似于在非调试构建中禁用 assert:你可以在 if __debug__ 中包装代码,如果检查在“优化”构建中太昂贵,或其他情况。__debug__ 非常有趣,因为尽管它是一个普通标识符(不同于 True、False 和 None),但它是语言中唯一不能被赋值的标识符:>>> __debug__ = 67 文件 """,第 1 行 SyntaxError: cannot assign to __debug__ 你甚至不能将其作为属性赋值:>>> x.__debug__ = 67 文件 """,第 1 行 SyntaxError: cannot assign to __debug__ 再一次,没有其他标识符表现得像这样。这真的是一个特例。但是因为它不是关键字,它的行为与 True、False 和 None 稍有不同:x.__debug__ 引发 AttributeError(而不是 SyntaxError),因为它在语法上是有效的;它只是在查找一个不存在的属性。有趣的是,尝试删除 __debug__ 也会有一个特别的错误信息(尽管如果不是特殊情况,这本身就会引发 NameError),但这并不适用于删除名为 __debug__ 的属性:>>> del __debug__ 文件 """,第 1 行 SyntaxError: cannot delete __debug__ >>> del x.__debug__ 回溯(最近的调用最先):文件 """,第 1 行,in NameError: name 'x' is not defined 如果 x 被定义了,相应地会引发 AttributeError。在这两种情况下,出于某种原因,这不是 SyntaxError(与赋值不同)。题外话:SyntaxError 是个谎言。谈到错误时:给 __debug__ 赋值是我所知道的唯一几个会引发 SyntaxError 的情况之一,尽管实际上没有什么无效的语法。这里,你可以自己验证:>>> assert (__debug__ := 67) 在调试构建中运行该 assert 会引发 SyntaxError,但使用 -O 时,断言不会被编译,从而不会引发异常。另两个这样的实例是使用 yield 或 await 在函数外部:>>> assert (yield) >>> assert (await 67) 省略号和 NotImplemented 省略号和 NotImplemented 在参考文献的 “常量” 部分有文档,但与其他 4 个常量不同,它们并不是 “真实的” 常量。它们只是普通的内置项,所以可以被全局变量覆盖:>>> NotImplemented = 67 >>> NotImplemented 67 再次,我对这里的理由感到好奇。为什么它们没有特别之处,而其他常量却有?覆盖常量 这里有件有趣的事:尽管是词法符号,但 True、False 和 None 也作为普通内置项存在:>>> import builtins >>> getattr(builtins, 'True') True >>> getattr(builtins, 'False') False >>> getattr(builtins, 'None') is None True 没办法不使用 getattr 直接访问这些。但是,这里事情变得真正有趣:setattr 也工作!>>> setattr(builtins, 'True', 67) >>> getattr(builtins, 'True') 67 然而,当通过词法符号访问时,这并不会改变其值:>>> True True 但 __debug__ 也有相同的行为!>>> setattr(builtins, '__debug__', 67) >>> builtins.__debug__ 67 >>> __debug__ True 所以 __debug__ 可以在某种程度上被赋值,但尽管它不是词法符号,它的特殊情况与 True、False 和 None 一样:其值不受内置模块更改的影响。因此,它确实是一个常量!省略号和 NotImplemented 再次不是实际的常量:>>> setattr(builtins, 'Ellipsis', 67) >>> Ellipsis 67 然而,这并不会改变 ... 的值:>>> ... Ellipsis 所以在某种意义上,... 是一个真正的常量,但 Ellipsis 不是。奇怪,对吧?

赞助内容

NordVPN Next-gen Antivirus

本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。

请我喝杯咖啡