72

私はこのパターン (またはアンチパターン) を発見し、とても満足しています。

私はそれが非常に機敏だと感じます:

def example():
    age = ...
    name = ...
    print "hello %(name)s you are %(age)s years old" % locals()

時々私はそのいとこを使用します:

def example2(obj):
    print "The file at %(path)s has %(length)s bytes" % obj.__dict__

人為的なタプルとカウント パラメーターを作成し、タプル内で %s の一致する位置を保持する必要はありません。

あなたはそれが好きですか?使いますか/使いますか? はい/いいえ、説明してください。

4

7 に答える 7

90

vars特に@kaizer.seによって言及された拡張機能と、@ RedGlyphによって言及されたバージョンでは、小さなアプリケーションや「1回限りの」スクリプトで問題あり.formatません。

ただし、メンテナンス寿命が長く、多くのメンテナがいる大規模なアプリケーションの場合、この方法はメンテナンスの問題につながる可能性があり、@S.Lottの答えはそこから来ていると思います。大規模なアプリケーション(またはそのような獣のための再利用可能なコンポーネント)の開発と保守に傷がない人には明らかではないかもしれないので、関連する問題のいくつかを説明しましょう。

「深刻な」アプリケーションでは、フォーマット文字列をハードコーディングする必要はありません。または、もしあれば、gettextから来るなど_('Hello {name}.')の形式になります。_または同様のi18n/L10nフレームワーク。重要なのは、そのようなアプリケーション(またはそのようなアプリケーションで使用される可能性のある再利用可能なモジュール)は、国際化(AKA i18n)とローカリゼーション(AKA L10n)をサポートする必要があるということです。国や文化、他のいくつかの「ホラポール」、他のいくつかの「チャオポール」など。したがって、現在のローカリゼーション設定に応じて、フォーマット文字列は実行時にほぼ自動的に別の文字列に置き換えられます。ハードコーディングされる代わりに、ある種のデータベースに存在します。すべての意図と目的のために、フォーマット文字列が文字列リテラルではなく、常に変数であると想像してください。

だから、あなたが持っているのは本質的に

formatstring.format(**locals())

また、フォーマットで使用されるローカル名正確に確認することはできません。L10Nデータベースを開いて熟読し、さまざまな設定でここで使用されるフォーマット文字列を特定し、それらすべてを確認する必要があります。

したがって、実際には、どのローカル名が使用されるのかわかりません。これは、関数の保守をひどく制限します。言語、ロケール、設定の組み合わせが(あなたにとって)あいまいなユーザーのユーザーエクスペリエンスをひどく損なう可能性があるため、ローカル変数の名前を変更したり削除したりしないでください。

優れた統合/回帰テストがある場合、ベータリリースの前に破損が検出されますが、QAが叫び、リリースが遅れます...そして、正直に言って、単体テストで100%のカバレッジを目指します合理的ですが、統合テストでは実際にはありません。設定の組み合わせ爆発[[L10Nおよびその他の多くの理由]]およびサポートされているすべての依存関係のバージョンを検討すると、したがって、「QAに巻き込まれる」ため、破損のリスクを軽率に回避することはありません(そうすると、大規模なアプリや再利用可能なコンポーネントを開発する環境では長続きしない可能性があります;-)。

したがって、実際には、ユーザーエクスペリエンスの人々がその挨拶をより適切な「ようこそ、恐ろしい大君主!」に長い間切り替えてきたとしても、「名前」ローカル変数を削除することは決してありません。(および適切にはそのL10n化バージョン)。あなたが行ったのですべてlocals()...

つまり、コードを維持および編集する能力をクリンプした方法のために、ごちゃごちゃしたものが蓄積されています。おそらく、その「名前」ローカル変数は、DBなどからフェッチされたためにのみ存在するので、それを維持します(または他のいくつかのローカル)周りはただのくだらないだけでなく、あなたのパフォーマンスも低下させています。そのlocals()価値のある表面の便利さはありますか?-)

しかし、待ってください、もっと悪いことがあります!lint同様のプログラム(たとえば、pylint )が実行できる多くの便利なサービスの中で、未使用のローカル変数について警告することです(未使用のグローバルに対しても実行できることを望みますが、再利用可能なコンポーネントの場合は、それだけです。少し難しすぎる;-)。このようにして、ユニットテストの中断を確認し、それが壊れた理由if ...: nmae = ...を見つけるために探偵作業を行うのではなく、非常に迅速かつ安価になど、ほとんどの場合に発生するスペルミスをキャッチします(最終的にこれキャッチする、執拗で普及したユニットテストがありますが右?-)-lintは未使用のローカル変数について通知し、すぐに修正します。nmae

しかし、コードにa blah.format(**locals())、または同等にblah % locals()...あなたはSOLです、仲間です!-)貧弱なlintnmaeは、実際に未使用の変数であるかどうか、または実際に外部関数で使用されているかどうかを知るのはどうですか?あなたが受け継いlocals()でいる方法?それはできません-とにかく警告する(「泣き虫」効果を引き起こし、最終的にそのような警告を無視または無効にする)か、警告することはありません(同じ最終効果:警告なし;-) 。

これを「暗黙的よりも明示的の方が優れている」代替案と比較してください...:

blah.format(name=name)

そこには、メンテナンス、パフォーマンス、およびam-I-hampering-lintの心配はもうありません。至福!関係するすべての人(lintを含む;-)に、正確にどのローカル変数がどの目的で使用されているかをすぐに明確にします。

続けることはできますが、この投稿はすでにかなり長いと思います;-)。

要約すると、「γνῶθισεαυτόν!」うーん、つまり「汝自身を知れ!」そして、「自分自身」とは、実際には「コードの目的と範囲」を意味します。それが1回限りのことで、i18nやL10nになることはなく、将来のメンテナンスはほとんど必要なく、より広いコンテキストで再利用されることはないなどの場合は、先に進んlocals()でそのために使用します小さいながらもすっきりとした便利さ。他のことを知っている場合、または完全に確信が持てない場合でも、注意を怠って、物事をより明確にします-あなたが行っていることを正確に綴るという小さな不便に苦しみ、結果として生じるすべての利点を享受します。

ところで、これはPythonが「小さな、1回限りの、探索的で、おそらくインタラクティブな」プログラミングの両方をサポートしようと努力している例の1つにすぎません(、、、、およびその他のいくつかのことをlocals()考えてくださいimport *。名前空間をマッシュアップし、利便性のためにメンテナンスの影響をリスクにさらす方法)、および「大規模で再利用可能なエンタープライズ向け」のアプリとコンポーネント。それは両方でかなり良い仕事をすることができます、しかしあなたが「自分自身を知っている」そしてあなたが実際にそれらを買う余裕があると絶対に確信しているときを除いて「便利な」部分の使用を避ける場合に限ります。多くの場合、重要な考慮事項は、「これは私の名前空間に何をするのか、そしてコンパイラ、lint&cによるそれらの形成と使用の認識です。evalexec

「名前空間は素晴らしいアイデアの1つです。もっと多くのことをしましょう!」これがPythonのZenの結論です...しかしPythonは、「同意する大人のための言語」として、開発環境、ターゲット、および実践の結果として、それが意味するものの境界を定義することができます。この力を責任を持って使用してください!-)

于 2009-10-11T17:14:09.967 に答える
11

決して百万年。書式設定のコンテキストが何であるかは不明localsです。ほとんどすべての変数を含めることができます。self.__dict__ほど曖昧ではありません。何がローカルで何がローカルでないかで将来の開発者が頭を悩ませるのはまったくもってひどいことです。

意図的な謎です。このような将来のメンテナンスの頭痛の種を組織に負わせる必要はありません。

于 2009-10-11T13:22:53.223 に答える
10

「いとこ」に関しては、の代わりにobj.__dict__、新しい文字列フォーマットを使用すると見栄えがよくなります。

def example2(obj):
    print "The file at {o.path} has {o.length} bytes".format(o=obj)

私はこれをreprメソッドによく使用します。

def __repr__(self):
    return "{s.time}/{s.place}/{s.warning}".format(s=self)
于 2011-05-24T06:32:44.943 に答える
10

組み込みの機能を利用して、記述する必要のあるコードを削減しているため、これは素晴らしいパターンだと思います。個人的にはかなりPythonicだと思います。

私は書く必要のないコードを書くことは決してありません - より少ないコードはより多くのコードよりも優れておりlocals()、たとえば、この使用法を使用することで、より少ないコードを書くことができ、非常に読みやすく、理解しやすくなります。

于 2009-10-11T11:28:56.373 に答える
8

"%(name)s" % <dictionary>またはさらに良いことに、の"{name}".format(<parameters>)メリットがあります

  • 「%0s」より読みやすい
  • 引数の順序から独立していること
  • 文字列内のすべての引数を使用する必要はありません

私は str.format() を好む傾向があります。これは Python 3 ( PEP 3101に従って) でそれを行う方法である必要があり、2.6 から既に利用可能になっているためです。locals()ただし、これを行う必要があります:

print("hello {name} you are {age} years old".format(**locals()))
于 2009-10-11T11:54:55.743 に答える
6

組み込みvars([object])( documentation ) を使用すると、2 番目の外観が良くなる場合があります。

def example2(obj):
    print "The file at %(path)s has %(length)s bytes" % vars(obj)

もちろん効果は同じです。

于 2009-10-11T13:15:38.983 に答える