10

私は単にあなたの時間を無駄にするつもりはありませんが、Python のwithステートメントを使用しているときに、「ネストされたものよりもフラットの方が優れている」という「Python の禅」の 5 行目に本当に反しているということをあなたにも思い浮かびましたか? 賢明な Python の第一人者で、これに関する洞察を共有してもらえますか?

with(私は常に、代わりにf.close()...を使用するたびに、コードにもう 1 レベルのインデントがポップアップすることに気付きますtry: ... finally: ...。とにかく使用しないわけではないので、好きになっても、その利点はwithまだわかりません。そしてPythonをますます理解する...)


@glglgl (申し訳ありませんが、コメントでコードを記述する方法が見つかりません): はいwith

try:
    with file(...) as f:
        ...
except IOError:
    ...

...そして、 with なしで with のみを使用することは、とにかく with の代わりにtry使用するハックな「1回限りの」コードのタイプで人々が行うことですf.close()(これは、例外が処理の前にスローされた場合にファイルが閉じられない可能性があるため、悪いことです) f.close())、つまり、「ハッキーな」コードの場合、人々はそれを使用しないだけです。withなぜなら、私にはわかりませんが、彼らはそれが「空想的」すぎると思うからだと思います。私には、実際のユースケースは残っていません... それは本当に考えていました。

4

5 に答える 5

8

はい、Zen of Pythonは「フラットはネストよりも優れている」と述べていますが、私たちが気にかけているのはそれだけではありません。また、「単純は複雑よりも優れている」とも述べています。の美しさは、以下で説明するように、これらの原則の両方withに実際に準拠していることです。

Python の機能について哲学的に熟考するときはいつでも、 Python Enhancement Proposals (PEP)を調べて、機能の背後にある動機について読む価値があるでしょう。この場合、PEP 343 -- 「with」ステートメントは、要約の中でそれを前もって述べています。

この PEP は、Python 言語に新しいステートメント "with" を追加して、try/finally ステートメントの標準的な使用法を排除できるようにします。

ステートメントを除外try/finallyすると、コードが単純になり、読みやすくなります。

ただし、 PEP 343は単純な構文糖衣を提供するだけではありません。コンテキスト マネージャー プロトコルを確立します。

ステートメント内の with キーワードの直後の式は「コンテキスト式」です。その式は、ステートメント本体の期間中にコンテキスト マネージャーが確立するランタイム環境に関する主要な手がかりを提供するからです。

コンテキスト マネージャー プロトコルを使用することで、API ライターは複雑さを隠し、マルチスレッド コンテキストでリソースを正しく取得/解放することができます。

withしかし、このステートメントの真の美しさはPEP 343の例 12 に示されています。

過剰なインデントを避けるために、指定されたコンテキストを左から右に自動的にネストする「ネストされた」コンテキスト マネージャー。

コンテキスト マネージャーを使用するnested()と、次のようなコードを取得できます。

with a as x:
    with b as y:
        with c as z:
            # Perform operation

そしてそれをこれに変えます:

with nested(a, b, c) as (x, y, z):
             # Perform operation

nested()は Python 2.5 で導入されましたが、バージョン 2.7 の時点で、この複数のコンテキスト マネージャーの構文形式を支持して非推奨になっていることに注意してください。

with a as x, b as y, c as z:
             # Perform operation

明らかに、これは単純で読みやすいだけでなく、ネストされたものよりもはるかにフラットです。したがって、使用with無爲のパスに従います:)

更新: Simeon Visser の回答に関するコメントへの回答として、複数のコンテキスト マネージャーを使用して一度に複数のファイルを開く場合、2 つ (またはそれ以上) のファイルの内容をまとめて圧縮する場合の例を次に示します。ファイルの 1 つが失敗すると、すべてが失敗し、開かれた各ファイルが適切に閉じられます。

from itertools import izip
with open("/etc/passwd") as a, open("/etc/group") as b, open("/etc/shadow") as c:
    for lines in izip(a,b,c):
        print map(lambda x: x.split(':')[0], lines)

この例を 2 回実行します。root として 1 回、通常のユーザーとして 1 回。このファイルを保存すると仮定すると、ziptogether.py最初に root として起動してみると成功しますが、読み取り権限がないためsudo python ziptogether.py、通常のユーザーとして起動すると失敗します。失敗した場合、コンテキスト マネージャーは、実行がステートメントのスコープ外に移動したときに、失敗する前に正常に開かれたファイルが適切に閉じられるようにします。python ziptogether.py/etc/shadowwith

于 2012-07-07T16:39:18.963 に答える
7

あなたはすでにそれについて言及しています:それはよりきれいです

f = file(...)
try:
    # do work on file
finally:
    f.close()

ファイル操作の後に閉じるだけではなく、例外が発生した場合には到達しません。

を と比較するtry/finallywith、同じレベルのインデントがあるため、何も失うことはありません。ただし、例外処理を行うと、さらに 1 レベルのインデントが発生します。これは、前述の禅のポイントに反します。

OTOH は、with物事をカプセル化し、それらをより簡単に、より読みやすくします。これは他の Zen の側面です。

常にすべての禅の側面に正確に従うことは、私には不可能に思えます。場合によっては、一方を他方と比較検討する必要があります。この場合、1 レベルのインデントが「失われ」ますが、読みやすさと保守性は向上します。後者は私にとって利点のようです。

于 2012-07-07T08:34:11.700 に答える
1
"Flat is better than nested"

さて、フラットとは何ですか?

import thirdparty
print "I Like Pie!"

vs

import org.example.thirdparty.something
System.out.println("I Like Cake")

等...

Zen of Pythonは、コードにインデント制限を適用するだけではありません。読みやすい(したがって、より良い)コードを書くことをお勧めします。withステートメントが3層のオブジェクト(など)からのみアクセスできる関数内にある場合one.two.three.func()、それは問題です。

それ以外の場合、3つのインデントレベルは他のレベルと同じくらい適切な数値です。

于 2012-07-07T10:50:36.737 に答える
1

を優先する理由は、関連する操作を手動でwithペアにする必要がないためです( /のように; しかし、構造はより一般的です -- ファイルを操作するためだけではありません)。これは、ソース コードから明確に見えない理由により 2 番目の操作が実行されない場合に重要です。あなたは機械が私の代わりにそれを処理してくれると言っていますが、この場合、機械は人間より優れています。このようにして、見つけにくい厄介なエラーのグループを取り除くことができます。open(...).close()with

ちなみに、のopen(...)代わりに使用する必要がありfile(...)ます。Python 3 は について何も知らないfile(...)ので、後でコードを修正する必要があります。

于 2012-07-07T12:36:27.593 に答える