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

Is there a need for a “use strict” Python compiler?

有针对python的静态分析工具,但编译时检查往往与python所采用的运行时绑定哲学截然相反。可以用静态分析工具包装标准的python解释器来强制执行一些"使用严格"的约束,但是我们没有看到这种东西被广泛采用。

关于python,是否有一些东西使"使用严格的"行为变得不必要或特别不受欢迎?

或者,尽管Perl被广泛采用,但在Perl中"使用严格"行为是否不必要?

注:"必要"是指"实际上必要",不是严格必要的。显然,您可以在不使用"use strict"的情况下编写Perl,但大多数Perl程序员确实使用它。

注意:python解释器包装不需要"use strict"类约束——您可以使用类似于"use strict"的伪pragma,这将被普通解释器忽略。我不是说要添加语言级别的功能。


更新:解释"use strict"在Perl per注释中的作用。(官方文件链接在第一段。)

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

  • 使用严格的变量:静态检查程序中词法范围的变量使用情况。(请记住,在python中,基本上只有global作用域和local作用域)。许多python linter都会检查这种情况。因为这是他们唯一能做的静态分析,所以linters假设你使用直接的词汇范围,并警告你在这个意义上出现错误的事情,直到你告诉他们闭嘴;也就是说。

    1
    2
    FOO = 12
    foo += 3

    如果您没有对名称空间做任何花哨的事情,那么这对于检查拼写错误很有用。

  • 使用严格引用:防止符号命名空间取消引用。python最接近的模拟方法是使用locals()globals()进行符号绑定和标识符查找。

  • 使用严格的subs:在python中没有真正的模拟。


好吧,我不是什么Python程序员,但我会说答案是"是"。好的。

任何允许您在任何时候使用任何名称创建变量的动态语言都可以使用"strict"杂注。好的。

Perl中的strict vars(在Perl中strict的选项之一,"use strict"会同时打开所有变量)要求在使用之前声明所有变量。这意味着该代码:好的。

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

在编译时生成致命错误。好的。

我不知道如何让Python在编译时拒绝此代码:好的。

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

您将得到一个运行时异常,即strict_iS_good未定义。但只有当代码被执行时。如果你的测试套件没有100%的覆盖率,你可以很容易地发布这个bug。好的。

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

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

注意,我关注的是perl中stict变量的语用效果,并对一些细节进行了润色。如果您真的想知道所有的细节,请参阅Perldoc以获得严格的信息。好的。

更新:对某些评论的答复好的。

杰森·贝克:像皮林特这样的静态跳棋很有用。但它们代表了一个可以并且经常被跳过的额外步骤。在编译器中构建一些基本检查可以保证这些检查的执行是一致的。如果这些检查是由一个语用控制的,甚至与检查成本相关的反对也变得没有意义。好的。

popcnt:我知道python将生成一个运行时异常。我也这么说。我提倡尽可能进行编译时检查。请重新阅读这篇文章。好的。

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

但是,这并不意味着不应进行任何检查。如果有一类问题很容易被发现,那么圈闭它们是有意义的。好的。

我对Pylint和PyChecker还不够熟悉,无法说出他们将捕获哪些类型的错误。正如我所说,我对Python非常缺乏经验。好的。

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

更新2:好的。

理论上,我同意你的观点,静态分析器可以做任何编译器可以做的验证。对于python来说,这就足够了。好的。

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

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

我的理解是,python没有pragma,不能在编译时运行任意代码。所以,除非我错了或者添加了这些特性,静态分析器中相对简单的解析器就足够了。在每次执行时强制执行这些检查当然会有所帮助。当然,我这样做的方式是使用一个pragma。好的。

一旦您向组合中添加了pragma,您就开始走下坡路了,分析器的复杂性必须随着您在pragma中提供的功能和灵活性的比例而增长。如果不小心,您可以像Perl那样结束,然后"只有Python可以解析Python",这是我不想看到的未来。好的。

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

(当我说Python不能像Perl那样使用编译时的行为时,绝不会贬低它的能力。我预感到这是一个经过深思熟虑的设计决策,我可以从中看到智慧。Perl在编译时的极端灵活性,imho,是该语言的一个巨大的优势和一个可怕的弱点;我也看到了这种方法的智慧。)好的。好啊。


"python采用的运行时绑定理念…使"严格使用"行为变得不必要[而且]特别不受欢迎

总结得不错。谢谢。

基本上就是这样。静态分析工具对Python的帮助不够大,不值得。

编辑

"我要求我们反省一下为什么我们不需要它,以及为什么Perl程序员认为他们确实需要它。"

原因正是你已经给出的原因。我们不需要它,因为它没有帮助。很明显,你不喜欢这个答案,但没什么好说的。编译时或预编译时检查根本没有帮助。

不过,既然你又花时间问了这个问题,我会为你已经给出的答案提供更多的证据。

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

虽然静态类型检查确实发现了方法偶尔的误用,但在Python中也可以很快发现这一点。在Python中,您会在单元测试时找到它,因为它不会运行。注意:我不是说在许多聪明的单元测试中发现了错误的类型,我是说大多数错误的类型问题都是通过未处理的异常发现的,在这些异常中,事情仅仅运行得不够远,无法测试断言。

为什么Python不在静态检查上浪费时间,原因很简单。我们不需要它。它没有任何价值。这是一个没有经济效益的分析水平。我再也不能用真实的数据来解决真实的人所面临的真正的问题了。

查看与语言(而不是问题域或库)相关的最流行的so-python问题。

"foo is none"和"foo==none"有什么区别吗?--==is的比较。没有静态检查可以帮助解决这个问题。另外,看看python中的`=`和` is'有什么区别吗?

**(双星)和*(星)对参数做了什么?--*x给出列表,**x给出字典。如果您不知道这一点,当您试图做一些不适合这些类型的事情时,您的程序会立即死亡。"如果你的程序从来没有做过"不适当"的事情呢?然后你的程序就开始工作了。"纳夫说。

如何在Python中表示"枚举"?--这是对某种有限域类型的请求。一个具有类级别值的类几乎可以完成这项工作。"如果有人改变了任务怎么办?易于建造。重写__set__以引发异常。是的,静态检查可能会发现这一点。不,在实践中不会有人对枚举常量和变量感到困惑;当他们这样做时,很容易在运行时发现。"如果逻辑永远不会被执行呢?嗯,那是糟糕的设计和糟糕的单元测试。抛出一个编译器错误,输入一个从未被测试过的错误逻辑,并不比在一个从未被测试过的动态语言中所发生的情况更好。

生成器表达式与列表理解——静态检查并不能帮助解决这个问题。

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

意外地反映在子列表中的列表更改列表——这完全是概念性的。静态检查也不能帮助解决这个问题。Java等价物也会编译和行为不良。


python确实具有可以更改脚本语法的功能:

1
from __future__ import print_function

以及其他具有语法含义的未来功能。只是python的语法比历史perl更严格、更稳定、定义更明确;而"strict refs"和"strict subs"禁止的语法在python中从未存在过。

"strict vars"主要是为了停止类型化的引用,并从创建意外全局(好吧,用perl术语来说,包变量)中漏掉"my"。这在Python中不可能发生,因为裸分配默认为本地声明,裸未分配的符号会导致异常。

(仍然存在这样的情况:用户不小心试图用"global"语句写入全局而不声明它,从而导致意外的本地错误,或者更常见的是,导致未绑定的本地错误。这一点很快就会被了解到,但这是一个有争议的案例,必须申报当地人才能有所帮助。尽管很少有经验丰富的Python程序员会接受可读性负担。)

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


从我看到的评论来看,"严格使用"的作用有些混乱。它不打开编译时类型检查(类似Java)。从这个意义上讲,Perl程序与Python程序员是一致的。正如S.Lott上面所说的,这些类型的检查并不能防止逻辑错误,也不能减少你需要编写的单元测试的数量,我们也不是束缚编程的狂热爱好者。

以下是"严格使用"的功能列表:

  • 使用符号引用是一个运行时错误。这可以防止你发疯(但有时是有用的事情,比如)

    $var = 'foo';

    江户十一〔一〕号

    埃多克斯1〔2〕

  • 使用未声明的变量是一个运行时错误(这意味着您需要在使用变量之前使用"my"、"our"或"local"来声明变量的作用域。

  • 所有空词都被认为是编译时语法错误。裸词是尚未声明为符号或子例程的词。这主要是为了取缔历史上曾做过但被认为是错误的事情。


  • python没有真正的词汇范围,所以严格的var不是很明智。它没有符号引用afaik,因此不需要严格的引用。它没有空词,所以不需要严格的变量。

    老实说,这只是我所错过的词汇范围。另外两个我认为是珍珠疣。


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

    There exist static analysis tools for Python, but compile time checks tend to be >diametrically opposed to the run-time binding philosophy that Python embraces.

    Perl中的"use strict"提供的功能是确保拼写错误或者变量名(通常)在编译时被捕获。这确实改善了代码可靠性,加速发展。但为了让这样的事情有价值,您需要声明变量。而Python风格似乎不鼓励这样做。

    因此,在python中,除非您注意到运行时,您认为您所做的任务没有被执行,或者表达式似乎解析为意外值。捕捉这些错误可能是耗时,尤其是当项目规模越来越大,人们被迫维持其他人开发的代码。

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


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

    Perl语言哲学不同于Python哲学。和中一样,在Perl中,我们给了您足够多的绳子来重复地挂起您自己。

    Larry Wall对语言学有很大的影响,所以我们从Perl得到了所谓的Timtowtdi(比如说tim-toe-dee原则与python的zen:

    There should be one-- and preferably
    only one --obvious way to do it.

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

    根据您对第一张海报的评论,您熟悉Python的import this。其中有很多东西可以解释为什么在python中看不到等同于use strict的东西。如果你冥想在Python禅宗中发现的Koan,你可能会为自己找到启示。:)


    在Perl中不使用"use strict"就很难编写大型程序。如果不使用"use strict",如果您再次使用一个变量,并在其中留下一个字母拼写错误,那么该程序仍将运行。如果没有测试用例来检查您的结果,就永远找不到这样的错误。因为这个原因,找出你为什么会得到错误的结果是非常耗时的。

    我的一些Perl程序由5000行到10000行代码组成,这些代码分成几十个模块。没有"use strict",就不能真正进行生产编程。我决不允许在工厂中使用不强制执行"变量声明"的语言安装生产代码。

    这就是为什么Perl5.12.x现在将"use strict"作为默认行为的原因。你可以把它们关掉。

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

    只是一个意见…

    abcparsing


    我发现我只关心检测未声明变量的引用。Eclipse通过pydev集成了pylint,尽管pylint还远远不够完美,但它在这方面做得很合理。

    它确实有点违背了Python的动态特性,当我的代码对某些事情变得很聪明时,我必须偶尔添加忽略。但我发现这种情况很少发生,我对此很满意。

    但是我可以看到一些类似于pylint的功能的实用程序以命令行标志的形式变得可用。类似于python 2.6的-3开关,它标识python2.x和3.x代码之间的不兼容点。


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


    "Python"代码的理想用途似乎与use strict有很多相同的用途。


    我没有Perl背景,但据我所知,在Python中没有需要禁用的特性,以便使代码"更可靠",因此从这个意义上说,我想您可以说这是不必要的