web-dev-qa-db-ja.com

Pythonにフォーマット関数とフォーマットメソッドがある理由

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

例えば。

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

明らかに好ましい

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

iMOの方が見栄えがよくなりますが、すべてのケースでstr.formatを使用して、物事を簡単にするのはなぜですか?これらは両方とも2.6で導入されたので、両方を同時に使用することには十分な理由があるはずです。それは何ですか?

編集:str.formatformatについて尋ねていましたが、(13).formatがない理由ではありませんでした

37
jamylak

formatと_str.format_は異なることをしていると思います。両方に_str.format_を使用することもできますが、バージョンを分けることは理にかなっています。

トップレベルのformat関数は、すべてのオブジェクトがサポートする新しい「フォーマットプロトコル」の一部です。渡されたオブジェクトの___format___メソッドを呼び出すだけで、文字列が返されます。これは低レベルのタスクであり、Pythonのスタイルは通常それらのための組み込み関数を持つことです。 Paulo Scardineの回答はこれの理論的根拠のいくつかを説明していますが、formatと_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___メソッドではなく、組み込みのformatを実際に呼び出すのではないかと思いますが、これは実装の詳細です。

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

使用法(スタックオーバーフローの例を含む)になると、一部のプログラマーがformatを知らないため、より多くの_str.format_の使用が見られる場合があります。対照的に、_str.format_を回避することは困難です(すべての書式設定で_%_演算子を使用することを決定した場合を除きます)。したがって、_str.format_呼び出しを理解することの容易さ(プログラマーと他のプログラマーにとって)は、パフォーマンスに関する考慮事項を上回る可能性があります。

8
Blckknght

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

それは構文上の砂糖です

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

format関数は、一部の [〜#〜] oo [〜#〜] 言語で見られるobj.format('fmt')構成の代替です。この決定は、lenの理論的根拠と一致しています(Pythonがプロパティの代わりに関数len(x)を使用する理由x.length like JavaScript またはRuby)。

言語がobj.format('fmt')構成(またはobj.lengthobj.toStringなど)を採用している場合、クラスはformat(またはlengthtoString、あなたはアイデアを得ました)-そうでなければ、それは言語から標準メソッドを隠します。この場合、言語設計者はプログラマーに名前の衝突を防ぐという負担を課しています。

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の duck-typed アプローチ [〜#〜] oo [ 〜#〜] そして、言語設計者に、レガシーコードを壊すことなく、基礎となる実装を変更/拡張する自由を与えます。

PEP 3101 は、新しいstr.formatメソッドとformatビルトインを導入しましたが、format関数の根拠に関するコメントはありませんが、実装は明らかにただ 構文糖

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

そしてここで私は私のケースを休ませる。

グイドはそれについて何を言った(またはそれは公式なのか?)

非常に引用 [〜#〜] bdfl [〜#〜] についてlen

まず第一に、私は [〜#〜] hci [〜#〜] 理由のためにlen(x)ではなくx.len()を選択しました(def __len__()はずっと後で来ました) 。実際には2つの理由が絡み合っています [〜#〜] hci [〜#〜]

(a)一部の演算では、接頭表記は単にpostfixよりも読みやすくなります。接頭辞(および下接!)演算は、数学において長い間、伝統があり、ビジュアルが問題について数学者が考える助けとなる表記法を好みます。 x*(a+b)のような数式をx*a + x*bに書き換える簡単な方法と、生のOO表記法を使用して同じことを行うことの不手際を比較してください。

(b)len(x)と書かれたコードを読んだとき、何かの長さを要求していることを知っています。これは2つのことを教えてくれます。結果は整数であり、引数はなんらかのコンテナです。逆に、x.len()を読んだとき、xは、インターフェイスを実装するか、標準のlen()を持つクラスから継承するコンテナの一種であることをすでに知っている必要があります。マッピングを実装していないクラスにget()またはkeys()メソッドが含まれている場合や、ファイルではないクラスにwrite()メソッドが含まれている場合に発生する混乱を確認してください。

同じことを別の言い方で言うと、「len」は組み込みの操作と見なされます。それを失うのは嫌だ。 /…/

出典: [email protected] (元の投稿 ここ には、Guidoが回答した元の質問もあります)。 Abarnert は以下も提案します:

デザインと履歴に関するFAQ には、lenに関する追加の推論があります。それは完全ではありませんし、答えの良いものでもありませんが、疑いもなく公式です。 – abarnert

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

これは、Python、 Ruby 、Javascriptなどの言語では非常に実用的で現実的な問題です。動的に型付けされた言語では、変更可能なオブジェクトは事実上名前空間であり、プライベートメソッドまたは属性の概念は重要です。コンベンション。多分私はそれを彼のコメントで abarnert よりも上に置くことができませんでした:

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

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

40
Paulo Scardine