是否需要"使用严格"的Python编译器?

cdl*_*ary 30 python compiler-construction perl static-analysis use-strict

存在用于Python的静态分析工具,但编译时间检查往往与Python所包含的运行时绑定哲学截然相反.这可能与一个静态分析工具来执行一些"包装标准Python解释器使用严格 "般的约束,但我们没有看到任何广泛采用的这样的事情.

有没有关于Python的东西会使"使用严格"的行为变得不必要或特别不受欢迎?

或者,Perl中的"使用严格"行为是否已被广泛采用?

注意:"必要"是指"实际必要",并非绝对必要.显然你可以在没有"use strict"的情况下编写Perl,但是(从我所见过的)大多数Perl程序员都会使用它.

注意:Python解释器包装器不需要 "使用严格"类似的约束 - 您可以使用类似于"use strict"的伪编译指示,这将被普通解释器忽略.我不是在谈论添加语言级功能.


更新:解释Perl每条评论中"use strict"的作用.(官方文档链接在第一段.)

"use strict"指令有三个不同的组件,其中只有两个非常有趣:

  • use strict vars:在程序中静态检查词法范围的变量用法.(请记住,在Python中,基本上只有global范围和local范围).许多Python短信检查这种事情.因为它是他们可以做的唯一的静态分析,所以直言不讳地假设你使用简单的词汇范围,并在你告诉他们闭嘴之前警告你那些看似错误的东西; 即

    FOO = 12
    foo += 3
    
    Run Code Online (Sandbox Code Playgroud)

    如果您没有对命名空间做任何想法,那么检查拼写错误就很有用.

  • use strict refs:防止符号命名空间解除引用.Python最接近的模拟是使用locals()globals()进行符号绑定和标识符查找.

  • use strict subs:在Python中没有真正的模拟.

dao*_*oad 35

好吧,我不是一个python程序员,但我会说答案是'是'.

任何时候都可以使用任何名称创建变量的动态语言都可以使用'strict'编译指示.

严格的变量(Perl中严格的选项之一,'use strict'一次全部打开它们)要求在使用之前声明所有变量.这意味着这段代码:

my $strict_is_good = 'foo';
$strict_iS_good .= 'COMPILE TIME FATAL ERROR';
Run Code Online (Sandbox Code Playgroud)

在编译时生成致命错误.

我不知道在编译时让Python拒绝这段代码的方法:

strict_is_good = 'foo';
strict_iS_good += 'RUN TIME FATAL ERROR';
Run Code Online (Sandbox Code Playgroud)

您将获得strict_iS_good未定义的运行时异常.但只有在代码执行时.如果您的测试套件没有100%的覆盖率,您可以轻松发送此错误.

每当我使用一种没有这种行为的语言(例如PHP)时,我就会感到紧张.我不是一个完美的打字员.一个简单但难以发现的拼写错误可能导致您的代码以可能难以追踪的方式失败.

因此,重申一下,YES Python可以使用'strict'编译指示打开编译时检查可以在编译时检查的内容.我想不出要添加的任何其他检查,但一个更好的Python程序员可能会想到一些.

注意我专注于Perl中stict vars的实用效果,并且掩盖了一些细节.如果你真的想知道所有细节,请参阅perldoc for strict.

更新:回复一些评论

Jason Baker:像pylint这样的静态检查器非常有用.但它们代表了一个可以并且经常被跳过的额外步骤.在编译器中构建一些基本检查可确保一致地执行这些检查.如果这些检查可以通过编译指控来控制,那么即使是与支票费用相关的异议也没有实际意义.

popcnt:我知道python会产生运行时异常.我说了很多.我主张在可能的情况下进行编译时检查.请重新阅读帖子.

mpeters:没有代码的计算机分析可以找到所有错误 - 这相当于解决了暂停问题.更糟糕的是,要在作业中找到拼写错误,您的编译器需要知道您的意图并找到您的意图与您的代码不同的地方.这显然是不可能的.

但是,这并不意味着不应该进行检查.如果存在易于检测的问题类别,则捕获它们是有意义的.

我不太熟悉pylint和pychecker来说明他们会捕捉到哪些类型的错误.正如我所说,我对python缺乏经验.

这些静态分析程序很有用.但是,我相信除非它们复制编译器的功能,否则编译器总是能够"了解"程序,而不是任何静态检查器.在可能的情况下不利用这一点来减少错误似乎是浪费.

更新2:

cdleary - 理论上,我同意你的观点,静态分析器可以进行编译器可以进行的任何验证.在Python的情况下,它应该足够了.

但是,如果您的编译器足够复杂(特别是如果您有许多编译指示可以更改编译的方式,或者像Perl一样,您可以在编译时运行代码),那么静态分析器必须接近编译器/解释器的复杂性做分析.

嘿,所有关于复杂编译器和编译时运行代码的讨论都显示了我的Perl背景.

我的理解是Python没有编译指示,并且在编译时无法运行任意代码.因此,除非我错了或添加了这些功能,否则静态分析器中的相对简单的解析器就足够了.在每次执行时强制执行这些检查肯定会有所帮助.当然,我这样做的方式是用一个pragma.

一旦你将pragma添加到混合中,你已经开始了一个滑坡,你的分析器的复杂性必须与你在pragma中提供的功能和灵活性成比例.如果你不小心,你可以像Perl一样结束,然后"只有python可以解析Python",这是我不希望看到的未来.

也许命令行开关是添加强制静态分析的更好方法;)

(当我说它不能像Perl那样的编译时行为时,不打算谴责Python的能力.我有一种预感,这是一个经过深思熟虑的设计决策,我可以看到它的智慧.Perl's编译时的极端灵活性,恕我直言,这是一种强大的力量和语言的可怕弱点;我也看到了这种方法的智慧.)

  • python是否"拒绝"使用您的术语的代码,但在运行时.一个体面的编辑器将有助于避免在perl和python中出现这样的错误 - 这就是重点 - >避免在源代码中包含意外错误. (2认同)

S.L*_*ott 12

"Python所包含的运行时绑定哲学......使得"使用严格"的行为变得不必要[和]特别不受欢迎"

非常好的总结.谢谢.

基本上就是这样.静态分析工具不足以使Python足够值得.


编辑

"我要求我们反思为什么我们不需要它,相关地,为什么Perl程序员认为他们确实需要它."

原因正是你已经给出的原因.我们不需要它,因为它没有帮助.显然,你不喜欢这个答案,但没有更多的话要说.编译时或预编译时检查无济于事.

但是,由于您花时间再次提出问题,我将为您已经给出的答案提供更多证据.

我写Java几乎和编写Python一样多.Java的静态类型检查不会阻止任何逻辑问题; 它不利于满足性能要求; 它无助于满足用例.它甚至不会减少单元测试的数量.

虽然静态类型检查确实发现偶尔滥用方法,但您在Python中发现这一点同样快.在Python中,您可以在单元测试时找到它,因为它不会运行.注意:我并不是说错误的类型被发现有很多聪明的单元测试,我说大多数错误的类型问题都是通过未处理的异常找到的,其中的东西根本不会运行到足以测试断言.

Pythonistas之所以不浪费时间进行静态检查很简单.我们不需要它.它没有任何价值.这是一个没有经济利益的分析水平.它不会让我更能解决真实的人对他们真实数据的真正问题.

看看最流行的SO Python问题是语言(不是问题域或库)相关的问题.

"foo is None"和"foo == None"之间有什么区别吗?- ==is.没有静态检查可以帮助解决这个问题 另外,请参阅Python中的`==`和`is`之间有区别吗?

**(双星)和*(星)对参数做了什么?- *x给出一个列表,**x给出一本字典.如果您不知道这一点,当您尝试对这些类型执行不适当的操作时,您的程序会立即死亡."如果你的程序从不做任何"不合适的事情怎么办?".然后你的程序工作.'努夫说.

我怎样才能用Python代表'Enum'? - 这是某种有限域类型的请求.具有类级别值的类几乎可以完成这项工作."如果有人改变任务怎么办".易于构建.覆盖__set__以引发异常.是静态检查可能会发现这一点.不,实际上没有人会对枚举常量和变量感到困惑; 当他们这样做时,很容易在运行时发现."如果逻辑永远不会被执行怎么办".嗯,这是糟糕的设计和糟糕的单元测试.抛出编译器错误并输入从未测试过的错误逻辑并不比从未测试过的动态语言更好.

生成器表达式与列表理解 - 静态检查无助于解决此问题.

为什么1 +++ 2 = 3? - 静态检查不会发现这一点.尽管进行了所有编译器检查,但C++中的1 +++ 2是完全合法的.它在Python中与在C中不同,但同样合法.同样令人困惑.

列表更改反映在子列表中的意外 - 这完全是概念性的.静态检查也无法解决这个问题.Java等价物也会编译并表现不佳.

  • -1,这只是一个咆哮,客观上是错误的.其他具有类似哲学的语言(Perl,JavaScript)从"使用严格"中获得了明显的好处,以至于它已成为一直使用它的既定最佳实践.Python将受益于同样的程度. (13认同)
  • 你的回答几乎等于,"这没有必要." 我知道很多Python代码已经成功编写而没有它 - 我要求我们反思*为什么*我们不需要它,相关地,为什么Perl程序员认为他们确实需要它. (9认同)
  • @ S.Lott:是的,但是你不想在上面提到的一个脚本中途,并因为你在编译时可以检测到的NameError而将它炸掉,对吗?有一个解释器包装器可以选择在编译时运行这个分析吗? (9认同)
  • @ S.Lott:大多数编写"脚本"(严格意义上说)的人不会编写单元测试,通常是因为有很多副作用的I/O. 单元测试对于应用程序/框架编程有意义,但对于脚本方案,检查标识符的编译器标志似乎很有用,不是吗? (6认同)
  • @cdleary:任何声称测试和脚本编写不一致的人都拒绝测试.他们需要开始一个远离软件的不同职业. (5认同)

bob*_*nce 11

Python确实有一些可以改变脚本语法的东西:

from __future__ import print_function
Run Code Online (Sandbox Code Playgroud)

以及具有语法含义的各种其他未来功能.只是Python的语法比历史Perl更严格,更稳定,更明确; Python中从不存在'严格参考'和'严格潜艇'禁止的东西.

'strict vars'主要是为了阻止拼写错误的引用,并且错过了'我的创建偶然的全局变量(以及Perl术语中的包变量).这在Python中不会发生,因为裸分配默认为本地声明,裸未分配符号会导致异常.

(仍然存在这样的情况:用户不小心尝试写入全局而没有使用'全局'语句声明它,导致意外本地或更常见的是UnboundLocalError.这往往会很快学会,但它是一个有争议的案例,必须声明你的本地人可以帮助.虽然很少有经验的Python程序员会接受可读性负担.)

不涉及语法的其他语言和库更改通过警告系统处理.


mpe*_*ers 7

从我所看到的评论来看,我认为存在一些混淆,就像"使用严格"一样.它不会打开编译时类型检查(就像Java一样).从这个意义上说,Perl程序员与python程序员是一致的.正如S.Lott所说,这些类型的检查不能防止逻辑错误,不要减少你需要编写的单元测试的数量,我们也不是束缚编程的忠实粉丝.

这是"use strict"的作用列表:

  1. 使用符号引用是运行时错误.这可以防止你疯狂(但有时候很有用)

    $var = 'foo';

    $foo = 'bar';

    print $$var; # this would contain the contents of $foo unless run under strict

  2. 使用未声明的变量是运行时错误(这意味着您需要使用"我的","我们的"或"本地"来声明变量的范围,然后再使用它.

  3. 所有裸字都被认为是编译时语法错误.Barewords是未被声明为符号或子例程的单词.这主要是为了取消历史上已经完成但被认为是错误的事情.


Leo*_*ans 5

Python没有真正的词汇范围,所以严格的变量不是很明智.它没有符号引用AFAIK,因此它不需要严格的引用.它没有赤字,所以它不需要严格的变量.

说实话,这只是我想念的词汇范围.另外两个我会考虑Perl中的疣.

  • 是的,Python是词法范围的.我认为指的是一个新的词法范围只是用一些特定的结构创建的:模块,类和函数.即for循环没有独立的封闭范围.如果在for循环中绑定标识符,它将保持绑定在它之外. (3认同)
  • 属性与词法范围几乎没有关系. (2认同)
  • @cdleary:是的,这就是我的意思. (2认同)

小智 5

这个原始答案是正确的,但可能并没有从实际意义上解释这种情况。

Python 存在静态分析工具,但编译时检查往往与 Python 所采用的运行时绑定哲学截然相反。

Perl 中的“use strict”提供的是确保(通常)在编译时捕获拼写错误或变量名称的能力。这确实提高了代码的可靠性,并加快了开发速度。但是为了让这样的事情变得有价值,你需要声明变量。Python 风格似乎不鼓励这样做。

因此,在 Python 中,您永远不会发现拼写错误的变量,直到您在运行时注意到您认为所做的赋值并未进行,或者表达式似乎解析为意外值。捕获此类错误可能很耗时,尤其是在程序变大以及人们被迫维护他人开发的代码时。

Java 和 C/C++ 更进一步,通过类型检查。动机是实际的,而不是哲学的。如何尽快捕获尽可能多的错误,并确保在将代码发布到生产环境之前消除所有错误?每种语言似乎都采用特定的策略并根据它们认为重要的内容运行。在像 Perl 这样不支持运行时绑定的语言中,利用“use strict”来简化开发是有意义的。


归档时间:

查看次数:

10824 次

最近记录:

11 年,2 月 前