【问题标题】:Why no 'const' in Python? [closed]为什么 Python 中没有“const”? [关闭]
【发布时间】:2013-06-21 22:09:02
【问题描述】:

我来自 C 背景,正在学习 Python。缺乏明确的类型安全令人不安,但我已经习惯了。面对动态语言的所有优势,缺乏内置的基于契约的编程(纯抽象类、接口)是需要习惯的。

但是,无法请求 const-cortectness 让我抓狂!为什么 Python 中没有常量?为什么不鼓励class-level constants

【问题讨论】:

  • “Python 中没有常量的等价物,因为程序员通常被认为足够聪明,可以单独留下一个他想保持不变的值”。
  • 因为 python 编码人员知道他们在做什么,而且还不够天真去修改应该是常量的变量(在 C 上下文中)
  • @Vorac,如果继续你的想法,那为什么 Python 中没有 intdoublechar 类型?.. 因为它是动态语言。如果你想要 Python 和 C 的“混合”,你可以看看 Cython 或 Go cython.org golang.org
  • 简短回答:这是一个观点问题。在另一个主题中,LISP 程序员曾经说过“内存分配太重要了,不能留给程序员”。并且“C 程序员认为内存分配太重要了,不能留给计算”(B. Stroustroup)。对于类型/常量的正确性,您可以说完全相同。

标签: python constants const-correctness


【解决方案1】:

C 和 Python 属于两种不同的语言。

前者是静态类型的。后者是动态的

在静态类型语言中,类型检查器能够推断每个表达式的类型,并在“编译”阶段检查它是否与给定的声明匹配。

在动态类型语言中,所需的类型信息直到运行时才可用。并且表达式的类型可能因一次运行而异。当然,您可以在程序执行期间添加类型检查。这不是在 Python 中做出的选择。这具有允许“鸭子打字”的优势。缺点是解释器无法检查类型的正确性。

关于 const 关键字。这是一个类型修饰符。限制允许使用的变量(有时修改允许的编译器优化)。在运行时检查动态语言的效率似乎很低。起初分析,这意味着要检查变量是否为 const 或不是每个做作。这可以进行优化,但即便如此,这样做是否值得?

除了技术方面,不要忘记每种语言都有自己的理念。在 Python 中,通常的选择是支持“约定”而不是“限制”。例如,常量应该全部大写。没有技术强制执行。这只是一个约定。如果您遵循它,您的程序将按照“其他程序员”的预期运行。如果您决定修改“常量”,Python 不会抱怨。但是应该觉得你在做“错事”。你打破了约定。也许你有你这样做的理由。也许你不应该有。你的责任。

最后一点,在动态语言中,程序的“正确性”更多地是单元测试的责任,而不是编译器的责任。如果你真的很难做到这一步,你会发现一些“代码检查器”。这些是PyLintPyCheckerPyFlakes...

【讨论】:

  • 动态编程没有限制。我应该能够很容易地定义 y(const x):。它基本上是“python 中的另一个问题:
  • 我同意 Erik Aronesty 的观点——在许多情况下,可以在“编译”时检查 const 合规性。应该可以保证变量在特定上下文中不会被直接修改,即使它的类型仅在运行时确定。
  • @user3204459 我不会争辩,因为我不擅长该领域,但您的建议强烈提醒我检查和传播变量可能修改的污染分析。使用静态分析,证明这是undecidable。另一方面,您可以添加一些运行时检查,但这会产生明显的开销。第三种方式,这可能是我最喜欢的方式,是让每一个数据不可变
  • @SylvainLeroux 是的,但是水密的污点分析可能超出了这里的建议。一个适度的替代方案是在编译时检查在变量被声明为常量的给定范围内,没有任何代码行修改变量或将其与非常量变量相关联(例如,通过函数调用)。类似于 C++ 提供的安全级别。无需跟踪每个变量直至每个可能的结果。
  • @user3204459 正确。如果你只考虑那个简单的模型,它可以像你提到的那样实现。但这意味着您必须以某种方式将参数的 const 状态存储在编译文件中,以便与预编译库正常工作(名称修改?)。即便如此,它真的能确保 const-correctness 吗? *args 和 **kwargs,或者通过存储在变量或集合(“函数指针”)中的函数对象的名称动态调用函数呢?也许我错了,但我认为即使使用您的简单模型,您仍然需要 runtime 常量检查。
【解决方案2】:

我不知道为什么做出这个设计决定,但我个人的猜测是没有明确的 const 关键字,因为常量的主要好处已经可用:

  • 常量适用于文档目的。如果你看到一个常数,你就知道你不能改变它。这也可以通过命名约定来实现。

  • 常量对于函数调用很有用。如果将常量作为参数传递给函数,则可以确保它不会被更改。在 Python 中,函数是“按值调用”,但由于 Python 变量是引用,因此您可以有效地传递引用的副本。在函数内部,您可以更改引用,但如果您重新分配它,更改不会在函数范围之外持续存在。因此,如果您将数字作为变量传递,它实际上是“像”常量一样传递的。您可以为变量分配一个新值。但是在函数之外,你还是得到了旧号码

此外,如果有 const 关键字,则会造成不对称:变量声明时没有关键字,而 const 声明时有关键字。合乎逻辑的结果是创建第二个名为 var 的关键字。这可能是一个品味问题。我个人更喜欢变量声明的简约方法。

如果您使用像元组这样的不可变数据结构,您可能可以获得更多的类型安全性。但是要小心,元组本身不能被修改。但如果它包含对可变对象的引用,即使它们属于元组,它们仍然是可变的。

最后你可能想看看这个 sn-p:http://code.activestate.com/recipes/65207-constants-in-python/?in=user-97991 我不确定这是否是“类级常量”的实现。但我认为它可能有用。

【讨论】:

  • 不存在不对称性:def y(const x):变量仍然没有关键字。 const,不是“变量”的有关键字
  • 请注意,只有传递给函数调用的不可变对象才会“像”常量一样“传递”。可以修改可变对象(列表、用户定义的类)。这是 const 有用的地方,它只允许重新分配而不是函数参数的突变。
  • @danio 传递一个不可变对象,如果您不信任该函数足以不改变您传递的内容。但请记住 Python 的口头禅:“我们都是同意的成年人”。如果一个函数改变了一个对象,它应该被记录下来。如果不是,则应记录为否。
  • @wizzwizz4 是的,我知道,我只是强调答案可能被误读为暗示参数“像”常量一样“传递”,而这仅适用于某些类型。关于记录函数的行为,这是一个很好的观点,这就是我喜欢其他语言中的 const 关键字的原因 - 它记录了行为,但以强制的方式,以便文档必须是正确的(如果声明了 constness) .
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-27
  • 2013-08-21
  • 2021-01-01
  • 1970-01-01
  • 2014-03-13
相关资源
最近更新 更多