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

时间:2009-03-05 02:08:25

标签: python perl compiler-construction static-analysis use-strict

存在static analysis tools for Python,但编译时间检查往往与Python所拥有的run-time binding philosophy截然相反。 可能使用静态分析工具包装标准Python解释器以强制执行某些“use strict”类似约束,但我们没有看到任何广泛采用此类事物。

有没有关于Python的内容会使“使用严格”的行为变得不必要或者特别不合适?

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

注意:“必要”是指“实际必要”,并非绝对必要。显然你可以编写没有“use strict”的Perl,但是(从我看到的)大多数Perl程序员使用它。

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


更新:解释每个评论中Perl的“use strict”。 (官方文档链接在第一段。)

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

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

    FOO = 12
    foo += 3
    

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

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

  • 使用严格的潜艇:在Python中没有真正的模拟。

12 个答案:

答案 0 :(得分:35)

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

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

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

my $strict_is_good = 'foo';
$strict_iS_good .= 'COMPILE TIME FATAL ERROR';

在编译时生成致命错误。

我不知道如何让Python在编译时拒绝这段代码:

strict_is_good = 'foo';
strict_iS_good += 'RUN TIME FATAL ERROR';

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

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

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

注意我专注于Perl中stict vars的实用效果,并且对某些细节进行了掩饰。如果您真的想知道所有细节,请参阅the perldoc for strict

更新:回复一些评论

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

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

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

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

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

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

更新2:

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

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

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

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

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

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

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

答案 1 :(得分:12)

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

非常好的总结。感谢。

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


修改

“我要求我们反省为什么我们不需要它,相关地,为什么Perl程序员认为他们确实需要它。”

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

但是,由于你花时间再次提出这个问题,我会提供更多证据来证明你已经给出的答案。

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

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

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

查看与语言(非问题域或库)相关的最受欢迎的SO Python问题。

Is there any difference between "foo is None" and "foo == None"? - ==is。没有静态检查可以帮助解决这个问题另请参阅Is there a difference between `==` and `is` in Python?

What does ** (double star) and * (star) do for parameters? - *x给出一个列表,**x给出一个字典。如果您不知道这一点,当您尝试对这些类型执行不适当的操作时,您的程序会立即死亡。 “如果你的程序从不做任何”不合适的事情怎么办?“。然后你的程序工作。 '努夫说。

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

Generator Expressions vs. List Comprehension - 静态检查无助于解决此问题。

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

List of lists changes reflected across sublists unexpectedly - 这完全是概念性的。静态检查也无法解决这个问题。 Java等价物也会编译并表现得很糟糕。

答案 2 :(得分:11)

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

from __future__ import print_function

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

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

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

通过warnings系统处理不涉及语法的其他语言和库更改。

答案 3 :(得分: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. 使用未声明的变量是运行时错误(这意味着您需要在使用之前使用“my”,“our”或“local”来声明变量的范围。

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

答案 4 :(得分:5)

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

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

答案 5 :(得分:4)

这个原始答案是正确的,但也许不能解释这种情况 在实际意义上。

  

存在用于Python的静态分析工具,但编译时间检查往往与Python所包含的运行时绑定哲学完全相反。

Perl提供的'严格'用法是确保错误拼写的能力 或者变量名称(通常)在编译时捕获。这确实改善了代码 可靠性,加快开发速度。但为了使这样的事情值得, 你需要声明变量。而Python风格似乎阻止了这一点。

所以在Python中,在你注意到之前,你永远不会发现错误拼写的变量 运行时你认为你所做的任务没有被制作,或者是 表达似乎解决了意想不到的值。抓住这样的错误可以 耗费时间,尤其是随着程序变大,以及人们被迫维护 由他人开发的代码。

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

答案 6 :(得分:3)

我认为Perl中的'use strict'更像是你所暗示的编译指示:它改变了编译器的行为。

Perl语言哲学与python哲学不同。在Perl中,你会被给予足够的绳索来反复挂起自己。

Larry Wall在语言学方面很重要,所以我们从Perl那里得到了所谓的TIMTOWTDI(比如tim-toe-dee)原则与禅宗的禅宗:

  

应该有一个 - 最好是   只有一种 - 显而易见的方式。

你可以很容易地使用pylint和PyChecker为python(或类似于use strict)提出自己的perl -cw *scriptname*风格,但由于语言设计中的不同哲学,你会在实践中没有遇到这种情况。

根据您对第一张海报的评论,您熟悉python的import this。那里有很多东西可以说明为什么你在Python中看不到等价的use strict。如果你冥想在Python的禅宗中找到的 koan ,你可能会为自己找到启示。 :)

答案 7 :(得分:1)

我发现我只关心检测对未声明的变量的引用。 Eclipse通过PyDev进行了pylint集成,虽然pylint远非完美,但它在这方面做得很合理。

它确实违背了Python的动态性质,当我的代码变得聪明时,我偶尔会添加#IGNOREs。但我发现这种情况很少发生,我很满意。

但我可以看到一些类似pylint的功能的实用程序以命令行标志的形式出现。有点像Python 2.6的-3开关,它识别Python 2.x和3.x代码之间的不兼容点。

答案 8 :(得分:1)

在Perl中编写没有'use strict'的大型程序是非常困难的。 没有'use strict',如果你再次使用一个变量,并通过留下一个字母拼错它,该程序仍然运行。如果没有测试用例来检查结果,就永远无法找到这样的错误。由于这个原因,找到导致错误结果的原因可能非常耗时。

我的一些Perl程序包含5,000行到10,000行代码,分为几十个模块。没有'use strict'就不能真正做生产编程。我永远不会允许使用不强制执行“变量声明”的语言在工厂中安装生产代码。

这就是为什么Perl 5.12.x现在将'use strict'作为默认行为。你可以关掉它们。

由于没有变量声明实施,PHP给了我很多问题。所以你需要用这种语言限制你自己的小程序。

只是意见......

abcParsing

答案 9 :(得分:0)

Perl是一种无拘无束的语言,他们说:)。所以你可以在宣布之前使用变量;例如:如果使用var名称“is_array”但输入“is_arrby”,则编译器不会在没有“use strict”的情况下报告错误。因此,在perl中编写长程序时,最好使用“use strict”语句。当然,运行一次脚本少于50行,没有必要:)

答案 10 :(得分:-2)

似乎“Pythonic”代码的理想与use strict具有很多相同的目的。

答案 11 :(得分:-3)

我没有Perl背景,但据我所知,python中没有任何功能需要被禁用才能让你的代码“更可靠”,所以在这个意义上,我想你可以说这是不必要的