Python 的预声明常量为何如此怪异
Python's pre-declared constants are kinda weird
Python 中有 6 个预声明的“常量”,但它们的底层行为却大相径庭。True、False 和 None 是真正的关键字,连 x.True 这样的写法都会直接触发 SyntaxError;而 __debug__ 虽能作为标识符,却唯独禁止赋值,甚至删除它也会报特殊错误。更奇怪的是,Ellipsis 和 NotImplemented 只是普通内置对象,可以被全局变量覆盖。最讽刺的是,即便你用 setattr 修改了 builtins 模块中 True 或 __debug__ 的值,代码中直接使用这些词时,它们的值依然纹丝不动。这种设计上的不一致,究竟源于什么考量?
给 __debug__ 赋值是我所知的少数几种情况之一:明明语法完全合法,却偏偏抛出了 SyntaxError。
HN 评论区
222- Revanche1367
Python 的许多设计决策在我看来都很怪异、格格不入,但长期以来,大家一直用这样的理由为其辩护:正是这些看似丑陋的小设计,让这门语言在实际使用中比那些设计更完美却几乎无人问津的语言更加易用和高效。我算不上专家,无法明确判断这是否属实,但在我看来,确实存在一种反复出现的模式:那些设计略显怪异的语言往往变得超级流行,比如 Python、JavaScript,或许还有 C。或者,也许我们之所以注意到这些怪异之处,仅仅是因为这些语言被使用得太广泛,从而被吹毛求疵到了极致。
- zahlman
之前的讨论:https://news.ycombinator.com/item?id=49284392(含我的评论),https://news.ycombinator.com/item?id=49250370。
这次看到它受到关注,真好。
- jherskovic
Python 拥有绝对强悍的库,即使没有 C 语言支持也是如此。对于像我这样喜欢开发 Web 应用却从未对 Ruby on Rails 一见钟情的人来说,它有 Django。而且 Django 简直太棒了。我也还没见过比它更适合编写快速 ETL 脚本和管道的语言。此外,还有那种“我需要写个脚本完成 $SYSADMIN_TASK,但希望以后还能读得懂”的场景。任何受外部延迟主导的任务(Web、数据库等),在 Python 中对于许多用途来说都已经足够快。
当然,它不是用来编写 Web 浏览器或游戏引擎的语言。而且它确实慢。但它在 ML/数据科学之外,仍有一些非常强势的细分领域。就我个人而言,我深爱它。各有所好罢了。
- nneonneo
__debug__ 这个常量真的很奇怪——任何被 `if __debug__:` 保护的代码块,在 PYTHONOPTIMIZE=1 下都会完全从字节码中省略。这以及 `assert` 是 Python 中仅有的两个真正的“条件编译”示例。这也是你不能给 __debug__ 赋值的原因:这样做会使得编译器关于 `if __debug__:` 语句的假设失效。
- neillyons
我记得读过,在 Python 的早期版本中,并没有内置的 True 和 False。每个用户都得自己实现:
True = 1
False = 0
后来这些才被加入到语言中。在 Python 2 中,你仍然可以重新赋值并交换它们,以至于 'if False' 实际上会变成真!
True, False = False, True
而在 Python 3 中,你再也无法重新赋值了。
- hmokiguess
Python 太烂了。库里有太多一次性方案,大家风格不统一,运行速度慢,而且太容易做错事。我经常和数据科学家合作,不得不把他们的 Jupyter 笔记本转化为生产代码,那简直是纯粹的次优地狱。我想,它可能确实适合科研或临时草稿,学习曲线很平缓吧。
- gucci-on-fleek
如果把预发布版本也算上,实际上有 7 个预声明常量,因为 Python 3.15(计划于 11 月发布 [0])将新增一个常量 "TYPE_CHECKING",其行为应类似于当前的 "Ellipsis" 和 "NotImplemented" [1]。
[0]: https://peps.python.org/pep-0790/#schedule
[1]: https://peps.python.org/pep-0781/#backwards-compatibility
- xg15
那么 "..." 不也是表现得像 True、False 和 None 一样吗?也就是说,它是一个在解析期间解析为硬编码值的词法标记?