38

ビルトインの関数は、単一のオブジェクトをフォーマットする場合に特に使用されるメソッドformatのサブセットのようです。str.format

例えば。

>>> format(13, 'x')
'd'

明らかに優先されます

>>> '{0:x}'.format(13)
'd'

そしてIMOは見た目が良くなりますがstr.format、すべての場合に使用して物事を簡単にしないのはなぜですか? これらは両方とも に導入された2.6ので、両方を同時に持つのには十分な理由があるに違いありません。それは何ですか?

編集:str.format私はとについて尋ねformatていました。(13).format

4

2 に答える 2

41

tldr; format呼び出して、さらに高レベルの処理を行うメソッドobj.__format__によって使用されます。str.format下位レベルでは、オブジェクト自体をフォーマットする方法をオブジェクトに教えることが理にかなっています。

それは単なる構文糖です

この関数が名前と形式の仕様を共有しているという事実は、str.format誤解を招く可能性があります。の存在str.formatは簡単に説明できます。複雑な文字列補間を行います (古い%演算子を置き換えます)。format仕様の最小のサブセットである文字列として単一のオブジェクトをフォーマットできますstr.format。では、なぜ必要なのformatでしょうか?

この関数は、一部のOO言語に見られる構造formatの代替です。この決定は、(Python がJavascriptや Rubyのようなプロパティの代わりに関数を使用する理由について)の論理的根拠と一致しています。obj.format('fmt')lenlen(x)x.length

言語がobj.format('fmt')コンストラクト (または など) を採用すると、クラスは (またはobj.length、おわかりのobj.toStringように) という名前の属性を持つことができなくなります。そうしないと、言語から標準メソッドが隠されます。この場合、言語設計者は名前の競合を防ぐという負担をプログラマーに課しています。formatlengthtoString

Python はPoLA__dunder__を非常に気に入っており、ユーザー定義の属性と言語の組み込みとの間の競合の可能性を最小限に抑えるために、組み込みに (二重下線) 規則を採用しています。もちろんの代わりに呼び出すことができます ( の代わりに呼び出すobj.format('fmt')ことができるのと同じ方法)。obj.__format__('fmt')obj.__format__('fmt')format(obj, 'fmt')obj.__len__()len(obj)

あなたの例を使用して:

>>> '{0:x}'.format(13)
'd'
>>> (13).__format__('x')
'd'
>>> format(13, 'x')
'd'

どちらがきれいで入力しやすいですか? Python の設計は非常に実用的であり、よりクリーンであるだけでなく、Python のダックタイプのオブジェクト指向アプローチとうまく連携しており、言語設計者はレガシー コードを壊すことなく、基礎となる実装を自由に変更/拡張できます。

PEP 3101は新しいstr.formatメソッドとformatビルトインをformat関数の理論的根拠についてのコメントなしで導入しましたが、実装は明らかに単なる構文糖衣です:

def format(value, format_spec):
    return value.__format__(format_spec)

そして、ここで私は自分のケースを休ませます。

それについてGuidoが言ったこと(またはそれは公式ですか?)

まさにBDFLの引用len:

まず第一に、私はHCIの理由で選択len(x)x.len()ました (かなり後で来ました)。実際には 2 つの絡み合った理由があり、どちらもHCIです。def __len__()

(a) 一部の演算では、前置記法は後置記法よりも読みやすい — 前置記法 (および中置記法!) 演算には、数学において長い伝統があり、ビジュアルが数学者が問題について考えるのに役立つ記法が好まれます。式を簡単に書き直すことと、生の OO 表記を使用して同じことを行うことの不器用さをx*(a+b)比較してください。x*a + x*b

len(x)(b)何かの長さを要求していることを知っているというコードを読んだとき。これは、結果が整数であることと、引数がある種のコンテナであることの 2 つを示しています。逆に、 を読むときはx.len()、それがxインターフェースを実装するか、標準のlen(). マッピングを実装していないクラスにget()orkeys()メソッドがある場合や、ファイルではない何かにメソッドがある場合に、時々混乱することがありますwrite()

同じことを別の言い方をすれば、「<code>len」は組み込み操作と見なされます。それを失うのはもったいない。/…/

ソース: pyfaq@effbot.org (ここの元の投稿には、Guido が回答していた元の質問も含まれています)。アバーナートは次のことも提案しています。

Design and History FAQに len に関する追加の理由があります。完全ではない、または適切な回答ではありませんが、間違いなく公式です。–アバーナート

これは実用的な問題ですか、それとも単なる構文の問題ですか?

これは、Python、 Ruby 、Javascriptなどの言語では非常に実用的で現実的な問題です。動的に型付けされた言語では、変更可能なオブジェクトは事実上名前空間であり、プライベート メソッドまたは属性の概念は慣例の問題だからです。おそらく、彼のコメントでabarnertよりもうまく言えませんでした。

また、Ruby と JS の名前空間汚染の問題に関しては、これが動的型付け言語に固有の問題であることを指摘しておく価値があります。Haskell や C++ などの多様な静的型付け言語では、型固有の自由関数が可能であるだけでなく、慣用的です。(インターフェイスの原則を参照してください。) しかし、Ruby、JS、Python などの動的型付け言語では、フリー関数は普遍的でなければなりません。動的言語の言語/ライブラリ設計の大部分は、そのような関数の適切なセットを選択することです。

たとえば、私は Ember での名前空間の競合にうんざりしていたので、 Ember.jsを残してAngular.jsを支持しました。Angular は組み込みメソッドの前に (Python のようなアンダースコアの代わりに Angular で) プレフィックスを付けるエレガントな Python のような戦略を使用してこれを処理するため、ユーザー定義のメソッドやプロパティと競合しません。はい、全体は特にきれいではありませんが、Python がこのアプローチを採用したことを嬉しく思います。これは非常に明示的であり、オブジェクトの名前空間の衝突に関するPoLAクラスのバグを回避できるからです。$thing__thing__

于 2013-05-22T05:09:44.933 に答える
8

いろいろなことを考えformatてやっています。str.format両方に使用できますがstr.format、別々のバージョンを使用することは理にかなっています。

トップレベルformat関数は、すべてのオブジェクトがサポートする新しい「フォーマット プロトコル」の一部です。__format__渡されたオブジェクトのメソッドを呼び出すだけで、文字列を返します。これは低レベルのタスクであり、Python のスタイルでは、通常、それらの組み込み関数を用意しています。formatPaulo Scardine の回答では、この理由の一部が説明されていますが、whatとdoの違いを実際に扱っているとは思いstr.formatません。

メソッドはstr.formatもう少し高レベルで、もう少し複雑です。複数のオブジェクトを 1 つの結果にフォーマットするだけでなく、オブジェクトに対して並べ替え、繰り返し、インデックス付け、およびその他のさまざまな変換を行うこともできます。だけを考えないでください"{}".format(obj)str.formatは、次のような複雑なタスク用に設計されています。

"{1} {0} {1!r}".format(obj0, obj1) # reorders, repeats, and and calls repr on obj1
"{0.value:.{0.precision}f}".format(obj) # uses attrs of obj for value and format spec
"{obj[name]}".format(obj=my_dict) # takes argument by keyword, and does an item lookup

各アイテムの低レベルのフォーマットについてstr.formatは、フォーマット プロトコルの同じメカニズムに依存しているため、より高いレベルのものに独自の努力を集中させることができます。format引数のメソッドではなく、実際に builtin を呼び出すとは思えませんが、それ__format__は実装の詳細です。

("{:"+format_spec+"}").format(obj)と同じ結果が得られることが保証されていformat(obj, format_spec)ますが、複雑なものをチェックするためにフォーマット文字列を解析する必要がないため、後者の方が少し速いと思います。ただし、実際のプログラムではオーバーヘッドがノイズで失われる場合があります。

使い方 (スタック オーバーフローの例を含む) に関してstr.format言えば、一部のプログラマーが について知らないという理由だけで、より多くの使い方が見られるかもしれませんformat。対照的に、これを回避するのは困難です (すべての書式設定で演算子をstr.format使用することに決めた場合を除きます)。%したがって、(あなたとあなたの仲間のプログラマーにとって)str.format呼び出しを理解することの容易さは、パフォーマンスに関する考慮事項を上回る場合があります。

于 2013-05-22T22:37:58.580 に答える