31

Python 用の静的解析ツールは存在しますが、コンパイル時のチェックは、Python が採用しているランタイム バインディングの哲学とは正反対の傾向があります。標準の Python インタープリターを静的分析ツールでラップして、「 use strict 」のような制約を強制することは可能ですが、そのようなものが広く採用されているとは思えません。

「厳密な使用」の動作を不要または特に望ましくないものにするPythonについて何かありますか?

あるいは、Perl が広く採用されているにもかかわらず、"use strict" 動作は Perl では不要ですか?

注: 「必要」とは、「実質的に必要」という意味であり、厳密には必要ではありません。明らかに「use strict」なしで Perl を書くことはできますが、(私が見た限りでは) ほとんどの Perl プログラマーそれを使用しています。

注: Python インタープリター ラッパーは、「use strict」のような制約を必要とする必要はありません通常のインタープリターでは無視される「use strict」と同様の疑似プラグマを使用できます。言語レベルの機能を追加することについて話しているのではありません。


更新: コメントごとに Perl で "use strict" が何をするかを説明します。(公式ドキュメントへのリンクは最初の段落にあります。)

「use strict」ディレクティブには 3 つの異なるコンポーネントがあり、そのうち 2 つだけが本当に興味深いものです。

  • use strict vars: プログラム内のレキシカル スコープ変数の使用を静的にチェックします。global(Python では、基本的にスコープとスコープしかないことに注意してくださいlocal)。多くの Python リンターは、この種のものをチェックします。それができる唯一の静的分析であるため、リンターは、あなたが単純な字句スコープを使用していると想定し、その意味で間違っているように見えることについては、あなたが黙るように言うまで警告します。すなわち

    FOO = 12
    foo += 3
    

    名前空間で特別なことをしていない場合、これはタイプミスをチェックするのに役立ちます。

  • use strict refs: シンボリック名前空間の逆参照を防ぎます。Python に最も近いものは、 and を使用locals()globals()てシンボリック バインディングと識別子の検索を行うことです。

  • use strict sub: Python には実際の類似物はありません。

4

10 に答える 10

37

私はあまり Python プログラマーではありませんが、答えは「YES」だと思います。

いつでも任意の名前の変数を作成できる動的言語では、'strict' プラグマを使用できます。

Perl の Strict vars (Perl の strict のオプションの 1 つで、'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) で作業するときはいつでも、緊張します。私は完璧なタイピストではありません。単純だが見つけにくいタイプミスが原因で、追跡が困難な方法でコードが失敗する可能性があります。

したがって、繰り返しますが、YES Python は「strict」プラグマを使用して、コンパイル時にチェックできるものに対してコンパイル時チェックをオンにすることができます。他に追加すべきチェックは思い浮かびませんが、より優れた Python プログラマーであれば、おそらくいくつか考えられるでしょう。

注意:私は Perl の stict vars の実際的な効果に焦点を当てており、詳細の一部については触れていません。本当にすべての詳細を知りたい場合は、perldoc の strictを参照してください。

更新: いくつかのコメントへの応答

Jason Baker : pylint のような静的チェッカーは便利です。しかし、それらはスキップされる可能性があり、多くの場合スキップされる余分なステップを表しています。いくつかの基本的なチェックをコンパイラに組み込むことで、これらのチェックが一貫して実行されることが保証されます。これらのチェックがプラグマによって制御可能である場合、チェックのコストに関連する異論も意味がありません。

popcnt : Python が実行時例外を生成することはわかっています。私はそれだけ言った。可能であれば、コンパイル時のチェックを推奨します。投稿を読み直してください。

mpeters : コードをコンピュータで分析しても、すべてのエラーを見つけることはできません。これは、停止の問題を解決することになります。さらに悪いことに、割り当てのタイプミスを見つけるために、コンパイラはユーザーの意図を知り、ユーザーの意図がコードと異なる場所を見つける必要があります。これは明らかに不可能です。

ただし、これは、チェックを行う必要がないことを意味するものではありません。検出しやすい問題のクラスがある場合、それらをトラップすることは理にかなっています。

私は、pylint と pychecker がどのクラスのエラーをキャッチするかについて十分に理解していません。私が言ったように、私はPythonに非常に不慣れです。

これらの静的解析プログラムは便利です。ただし、コンパイラの機能を複製しない限り、コンパイラは常に、静的チェッカーよりもプログラムについてより多くのことを「知る」立場にあると私は信じています。可能な限りエラーを減らすためにこれを利用しないのはもったいないようです。

更新 2:

cdleary - 理論的には、静的アナライザーはコンパイラーができる検証を行うことができます。そして Python の場合は、それで十分なはずです。

ただし、コンパイラが十分に複雑な場合 (特に、コンパイルの方法を変更するプラグマが多数ある場合、または Perl のようにコンパイル時にコードを実行できる場合)、静的アナライザーはコンパイラー/インタープリターの複雑さにアプローチして、分析を行います。

へー、複雑なコンパイラとコンパイル時のコードの実行に関するこのすべての話は、私の Perl のバックグラウンドを示しています。

私の理解では、Python にはプラグマがなく、コンパイル時に任意のコードを実行することはできません。したがって、私が間違っているか、これらの機能が追加されていない限り、静的アナライザーの比較的単純なパーサーで十分です。実行ごとにこれらのチェックを強制することは確かに役に立ちます。もちろん、これを行う方法はプラグマを使用することです。

プラグマをミックスに追加すると、滑りやすい坂道を下り始めたことになります。アナライザーの複雑さは、プラグマで提供するパワーと柔軟性に比例して増加する必要があります。注意を怠ると、Perl のようになってしまい、"Python だけが Python を解析できる" という、私が望んでいない未来になる可能性があります。

強制静的解析を追加するには、コマンド ライン スイッチの方が適しているかもしれません ;)

(Python が Perl のようにコンパイル時の動作を混乱させることはできないと私が言うとき、決して Python の機能を非難するつもりはありません。これは慎重に検討された設計上の決定であり、そこに知恵があることがわかります。Perl のコンパイル時の極端な柔軟性は、私見ですが、この言語の大きな強みであり、ひどい弱点でもあります; 私はこのアプローチにも知恵があると思います.)

于 2009-03-05T15:37:14.737 に答える
11

Python には、スクリプトの構文を変更できるものがあります。

from __future__ import print_function

および構文に影響を与えるその他のさまざまな将来の機能。Python の構文は、歴史的な Perl よりも厳密で、安定しており、明確に定義されています。「strict refs」と「strict subs」が禁止する種類のものは、Python には存在しませんでした。

'strict vars' は主に、タイプミスした参照や見落とした 'my's が偶発的なグローバル (Perl 用語ではパッケージ変数) を作成するのを防ぐことを目的としています。これは Python では発生しません。裸の割り当てはデフォルトでローカル宣言になり、裸の未割り当てのシンボルは例外になります。

(ユーザーが 'global' ステートメントでグローバルを宣言せずに誤ってグローバルにライトスルーしようとするケースがまだあり、偶発的なローカルまたはより頻繁に UnboundLocalError が発生します。これはかなり迅速に学習される傾向がありますが、ローカル変数を宣言する必要がある場合は議論の余地がありますが、経験豊富な Python プログラマーで可読性の負担を受け入れる人はほとんどいません)。

構文を伴わないその他の言語およびライブラリの変更は、警告システムを通じて処理されます。

于 2009-03-05T02:54:53.507 に答える
9

「Pythonが採用しているランタイムバインディング哲学は、「厳密な使用」動作を不要にします[そして]特に望ましくありません」

かなり良い要約。ありがとう。

それは本質的にそれです。静的分析ツールは、Pythonを十分に価値のあるものにするのに役立ちません。


編集

「なぜそれが必要ないのか、そしてそれに関連して、Perlプログラマーがなぜそれが必要だと思うのかを内省するように求めています。」

理由はまさにあなたがすでに与えた理由です。それは役に立たないので、私たちはそれを必要としません。明らかに、あなたはその答えが好きではありませんが、言うべきことはあまりありません。コンパイル時またはプリコンパイル時のチェックは、単に役に立ちません。

しかし、あなたはもう一度質問をするのに時間がかかったので、私はあなたがすでに与えた答えのより多くの証拠を提供します。

私はPythonを書くのとほぼ同じくらいJavaを書いています。Javaの静的型チェックは、ロジックの問題を防ぐことはできません。パフォーマンス要件を満たすことは容易ではありません。ユースケースを満たすのに役立ちません。単体テストの量を減らすことすらありません。

静的型チェックはメソッドの時折の誤用を発見しますが、Pythonでも同じようにすばやく発見できます。Pythonでは、実行されないため、単体テスト時に見つかります。注:多くの巧妙な単体テストで間違ったタイプが見つかると言っているのではありません。ほとんどの間違ったタイプの問題は、アサーションをテストするのに十分な距離まで実行されない未処理の例外によって見つかると言っています。

Pythonistasが静的チェックに時間を浪費しない理由は簡単です。必要ありません。それは何の価値も提供しません。これは、経済的利益がないレベルの分析です。実際の人々が実際のデータで抱えている実際の問題を解決することはできなくなります。

言語(問題のあるドメインやライブラリではない)に関連する最も人気のあるSOPythonの質問を見てください。

「fooisNone」と「foo==None」の違いはありますか?-==is。静的チェックはこれに役立ちません。また、Pythonの `==`と`is`には違いがありますか?を参照してください。

**(二重星)と*(星)はパラメーターに対して何をしますか?--*xリストを**x提供し、辞書を提供します。これがわからない場合、これらのタイプに不適切なことを行おうとすると、プログラムはすぐに終了します。「もしあなたのプログラムが「不適切な」ことを決してしないとしたらどうでしょう」。その後、プログラムが機能します。'言っ途切れる。

Pythonで「列挙型」を表すにはどうすればよいですか?-これは、ある種の限定ドメインタイプに対する罪状認否です。クラスレベルの値を持つクラスは、ほとんどその仕事をします。「誰かが割り当てを変更した場合はどうなりますか」。簡単に構築できます。オーバーライド__set__して例外を発生させます。はい、静的チェックでこれを見つけることができます。いいえ、実際には、誰かが列挙型定数と変数について混乱することはありません。その場合、実行時に簡単に見つけることができます。「ロジックが実行されない場合はどうなりますか」。まあ、それは貧弱な設計と貧弱な単体テストです。コンパイラエラーをスローし、テストされていない間違ったロジックを挿入することは、動的言語がテストされていないときに発生することよりも優れています。

ジェネレータ式とリスト内包表記-静的チェックはこの質問の解決に役立ちません。

なぜ1+++2 = 3なのですか?--静的チェックではこれを検出できません。Cの1+++2は、すべてのコンパイラチェックにもかかわらず、完全に合法です。PythonでもCと同じではありませんが、同じように合法です。そして、同じように紛らわしい。

リストのリストの変更がサブリスト全体に予期せず反映されました-これは完全に概念的なものです。静的チェックもこの問題の解決に役立ちません。Javaに相当するものもコンパイルされ、動作が悪くなります。

于 2009-03-05T03:36:24.453 に答える
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. すべてのベアワードは、コンパイル時の構文エラーと見なされます。ベアワードは、シンボルまたはサブルーチンとして宣言されていない単語です。これは主に、歴史的に行われたが間違いであると考えられることを禁止するためのものです。

于 2009-03-05T12:27:03.430 に答える
5

この元の答えは正しいですが、おそらく実際的な意味で状況を説明していません。

Python 用の静的解析ツールは存在しますが、コンパイル時のチェックは、Python が採用しているランタイム バインディングの哲学とは正反対の傾向があります。

Perl で「use strict」が提供するのは、スペルミスまたは変数名が (通常) コンパイル時にキャッチされることを保証する機能です。これにより、コードの信頼性が向上し、開発がスピードアップします。しかし、そのようなことを価値あるものにするためには、変数を宣言する必要があります。そしてPythonスタイルはそれを思いとどまらせているようです.

したがって、Python では、変数のスペルが間違っていても、実行時に自分が行ったと思っていた代入が行われていないことに気付くまで、または式が予期しない値に解決されているように見えるまで、決して見つけることはありません。特にプログラムが大きくなり、他の人が開発したコードを維持する必要がある場合は特に、このようなエラーを検出するのに時間がかかることがあります。

Java と C/C++ では、型チェックを使用してさらに一歩進んでいます。動機は哲学的ではなく、実用的です。できるだけ早くできるだけ多くのエラーを検出し、コードを本番環境にリリースする前にすべてのエラーを確実に排除するにはどうすればよいでしょうか? それぞれの言語は、彼らが重要だと考えるものに基づいて、特定の戦略を取り、それを実行しているようです. 実行時バインディングがサポートされていない Perl のような言語では、'use strict' を利用して開発を容易にすることは理にかなっています。

于 2010-11-10T00:28:43.933 に答える
4

Python には真のレキシカル スコープがないため、厳密な vars はあまり賢明ではありません。AFAIKにはシンボリック参照がないため、厳密な参照は必要ありません。ベアワードがないため、厳密な変数は必要ありません。

正直なところ、私が見逃しているのはレキシカルスコープだけです。他の 2 つは、Perl の疣贅と考えます。

于 2009-03-05T12:25:19.517 に答える
3

あなた'use strict'がほのめかしたように、Perlのはプラグマのようなものだと思います。コンパイラの動作を変更します。

Perl 言語の哲学は Python の哲学とは異なります。たとえば、Perl では、繰り返し首を吊るすのに十分な数のロープが与えられます。

Larry Wall は言語学に熱心なので、Perl から TIMTOWTDI (たとえばtim-toe-dee) 原則と Python の Zenと呼ばれるものがあります。

それを行う明白な方法が 1 つ (できれば 1 つだけ) ある必要があります。

pylint と PyChecker を使用して独自のuse strictfor python (または に類似したものperl -cw *scriptname*) を簡単に作成できますが、言語設計の哲学が異なるため、実際にはこれに広く遭遇することはありません。

最初のポスターへのコメントに基づいて、あなたは python のimport this. use strictそこには、Pythonで に相当するものが表示されない理由を明らかにするものがたくさんあります。Zen of Python にある公案を瞑想すると、自分自身の悟りが見つかるかもしれません。:)

于 2009-03-05T02:57:31.660 に答える
1

私は、宣言されていない変数への参照を検出することだけを本当に気にかけていることがわかりました。EclipseにはPyDevを介したpylint統合があり、pylintは完璧にはほど遠いですが、それで妥当な仕事をします。

これはPythonの動的な性質に反するものであり、コードが何かについて巧妙になったときに、時々#IGNOREを追加する必要があります。しかし、それはめったに起こらないので、私はそれに満足しています。

しかし、いくつかのpylintのような機能のユーティリティがコマンドラインフラグの形で利用可能になるのを見ることができました。Python 2.6の-3スイッチのようなもので、Python2.xと3.xのコード間の非互換性のポイントを識別します。

于 2009-03-05T19:25:17.403 に答える
0

Perlで「usestrict」なしで大きなプログラムを書くことは非常に困難です。'use strict'を使用せずに、変数を再度使用し、文字を省略してスペルを間違えた場合でも、プログラムは実行されます。そして、結果をチェックするためのテストケースがなければ、そのようなエラーを見つけることはできません。この理由で間違った結果が得られる理由を見つけるのは非常に時間がかかる場合があります。

私のPerlプログラムのいくつかは、5,000行から10,000行のコードで構成されており、数十のモジュールに分割されています。'usestrict'なしでは実際にプロダクションプログラミングを行うことはできません。「変数宣言」を強制しない言語を使用して、製品コードをファクトリにインストールすることは決して許可しません。

これが、Perl5.12.xがデフォルトの動作として「usestrict」を備えている理由です。それらをオフにすることができます。

PHPは、変数宣言が強制されていないため、かなりの問題を抱えています。したがって、この言語を使用する小さなプログラムに限定する必要があります。

ただの意見...

abcParsing

于 2011-07-18T23:44:44.347 に答える