首页 时政热点 科技头条 智能AI 安全攻防 数码硬件 开发者生态 汽车 游戏 社会热点 开源推荐 医疗健康 归档 标签 关于

Python 的预声明常量有点奇怪

摘要

python has 6 pre-declared "constants": True , False , None , __debug__ , Ellipsis (or equivalently ... ), and NotImplemented . but they all behave slightly differently, for some reason. True , False ,...

__debug__ the True this False None and but for SyntaxError
2026-08-26 1 阅读 约7分钟阅读 rbanffy
分享:
字号:
python 有 6 个预先声明的“常量”: True 、 False 、 None 、 __debug__ 、 Ellipsis (或等效的...)和 NotImplemented 。但由于某种原因,它们的行为都略有不同。 True 、 False 和 None True 、 False 和 None 是关键字。它们不是标识符,它们只是它们自己的词汇标记。这真的很奇怪; python 中没有其他东西是这样的。通常,内容是在常规名称解析期间解析的,而不是在词法分析器本身中解析的。这样做的一个有趣的副作用是像 x.True 这样的表达式会引发 SyntaxError 。我很好奇这个决定的理由是什么(如果有的话)。这些常量还有一些更有趣的内容,但我稍后会讨论它,因为它与其他常量相关。 __debug__ __debug__ 是一个布尔常量:它通常是 True ,但是当使用 -O 运行时,它是 False 。这个想法类似于在非调试构建中禁用断言的方式:如果检查在“优化”构建等中过于昂贵,则可以将代码包装在 if __debug__ 中。不过 __debug__ 确实很有趣,因为虽然它是一个普通标识符(与 True 、 False 和 None 不同),但它是该语言中唯一不能分配给的标识符: >>> __debug__ = 67 File " ", line 1 SyntaxError: 无法分配给 __debug__ 你甚至不能将它分配为属性: >>> x.__debug__ = 67 File " ", line 1 SyntaxError: Cannot allocate再次 __debug__ ,没有其他标识符有这样的行为。这是一个真正的特殊情况。但因为它不是关键字,所以它的行为与 True 、 False 和 None 略有不同: x.__debug__ 引发 AttributeError (而不是 SyntaxError ),因为它在语法上是有效的;它只是查找一个不存在的属性。有趣的是,尝试删除 __debug__ 时还会出现一条特殊的错误消息(尽管事实上,如果不是特殊情况,这无论如何都会引发 NameError),但这不适用于删除名为 __debug__ 的属性: >>> del __debug__ File " ", line 1 SyntaxError: Cannot delete __debug__ >>> del x.__debug__ Traceback (most最近的调用最后): File " ", line 1, in NameError: name如果定义了 x,则未定义“x”,则会引发 AttributeError。无论哪种情况,由于某种原因,它都不是 SyntaxError (与赋值不同)。切线:SyntaxError 是一个关于错误的谎言:分配给 __debug__ 是我所知道的少数情况之一,尽管某些内容实际上并不是无效语法,但会引发 SyntaxError 。在这里,您可以自己确认: >>> assert (__debug__ := 67) 在调试版本中运行该断言会引发 SyntaxError ,但使用 -O 时,断言永远不会被编译,因此不会引发异常。另外两个实例在函数外部使用yield或await:>>>断言(yield)>>>断言(await 67)省略号和NotImplemented省略号和NotImplemented记录在参考文献的“常量”部分中,但与其他4个常量不同,它们不是“真正的”常量。它们只是普通的内置函数,因此它们可以被全局变量遮盖: >>> NotImplemented = 67 >>> NotImplemented 67 再次,我很好奇这里的基本原理。为什么这些常数并不特殊,而其他常数却很特殊?覆盖常量这里有一些有趣的事情:尽管是词法标记, True 、 False 和 None 也作为普通内置函数存在: >>> importbuiltins >>> 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 一样:它的值不受内置模块更改的影响。所以它确实是一个常数!再次强调,Ellipsis 和 NotImplemented 实际上并不是常量: >>> setattr(builtins, 'Ellipsis', 67) >>> Ellipsis 67 这不会改变 ... 的值: >>> ... Ellipsis 所以在某种意义上, ... 是一个真正的常量,但 Ellipsis 不是。很奇怪,对吧?
这篇文章对您有帮助吗?

订阅66必读

每日精选科技资讯,直达你的邮箱