24

Pythonの内部(CPythonまたは他の実装)に精通している人は、リストの追加が同種である必要がある理由を説明できますか?

In [1]: x = [1]

In [2]: x+"foo"
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
C:\Users\Marcin\<ipython-input-2-94cd84126ddc> in <module>()
----> 1 x+"foo"

TypeError: can only concatenate list (not "str") to list

In [3]: x+="foo"

In [4]: x
Out[4]: [1, 'f', 'o', 'o']

上記が上記のトランスクリプトx+"foo"の最終値と同じ値を返さないのはなぜですか?x

この質問は、ここでのNPEの質問に続くものです。Pythonのリストの動作+ =反復可能であるかどうかは、どこにでも文書化されていますか?

更新:異種の作業は必須ではないことを私は知っています+=(しかし、そうします)。同様に、異種の作業が+エラーである必要はありません。この質問は、なぜ後者の選択がなされたのかについてです。

リストにシーケンスを追加した結果が不確実であると言っても過言ではありません。それが十分な異議である場合、異質性を防ぐことは理にかなってい+=ます。Update2:特に、Pythonは常に演算子の呼び出しを左側のオペランドに委任するため、「何をするのが正しいか」という問題は発生しません。左側のオブジェクトが常に支配します(右側に委任しない限り)。

Update3:これが設計上の決定であると主張する人のために、(a)それが文書化されていない理由を説明してください。または(b)文書化されている場合。

Update4:「何を[1] + (2, )返す必要がありますか?」の直後にx最初に保持されている変数の値と等しい結果値を返す必要があります。この結果は明確に定義されています。[1]x+=(2, )

4

4 に答える 4

11

Zen of Python から:

あいまいさに直面しても、推測する誘惑を断ってください。

ここで何が起こるか見てみましょう:

x + y

これにより値が得られますが、どのタイプでしょうか? 実生活で何かを追加するとき、型が入力型と同じであることを期待しますが、それらが異なる場合はどうなるでしょうか? 現実の世界では、追加を拒否し、1意味"a"がありません。

似たようなタイプがいる場合はどうなりますか?現実の世界では、コンテキストを見ます。コンピューターはこれを行うことができないため、推測する必要があります。Python は左側のオペランドを選択し、それを決定させます。このコンテキストの欠如が原因で問題が発生します。

プログラマーがやりたいと言ってください["a"] + "bc"- これは彼らがしたい"abc"、または["a", "b", "c"]. 現在、解決策は"".join()、最初のオペランドまたはlist()2 番目のオペランドのいずれかで呼び出すことです。これにより、プログラマーは自分のやりたいことを明確かつ明示的に行うことができます。

あなたの提案は、Pythonが推測することです(特定のオペランドを選択する組み込みのルールを持つことにより)ので、プログラマーは加算を行うことで同じことを行うことができます-なぜそれが良いのですか? これは、誤って間違った型を取得しやすくなることを意味するだけであり、任意の規則を覚えておく必要があります (左のオペランドが型を選択する)。代わりに、正しい呼び出しを行うために必要な情報を Python に提供できるように、エラーが発生します。

ではなぜ+=違うのでしょうか?それは、Python にそのコンテキストを与えているからです。インプレース操作では、Python に値を変更するように指示しているため、変更しようとしている値の型を扱っていることがわかります。これは、Python が正しい呼び出しを行うために必要なコンテキストであるため、推測する必要はありません。

推測について話すときは、Python がプログラマーの意図を推測することについて話しているのです。これは Python がよく行うことです - 3.x の除算を参照してください。/2.x での整数除算のエラーを修正して、浮動小数点除算を行います。

これは、除算を試みるときに暗黙的に float 除算を要求しているためです。Python はこれを考慮に入れ、それに従って操作を行います。同様に、ここでは意図を推測することについてです。+私たちの意図でいつ追加するかは不明です。を使用する+=と、非常に明確です。

于 2012-12-16T20:53:52.693 に答える
9

これらのバグ レポートは、この設計上の癖が誤りであることを示唆しています。

問題 12318 :

はい、これは予想される動作であり、一貫性がありません。

それは長い間そうであり、グイドは二度とやらないと言った(それは彼の後悔のリストにある). ただし、コードを変更してコードを壊すつもりはありません (list.__iadd__のように動作しlist.extendます)。

問題 575536 :

その意図は、list.__iadd__に正確に対応する ことでしたlist.extend()。過度に一般化する必要もありませ list.__add__()ん。これは、Martin のような例に驚かされたくない人が、plain +for リストを使用することでそれらを回避できる機能です。

(もちろん、そのバグ レポートを開いた開発者を含め、この動作を非常に驚くべきものと考える人もいます)。

(これらを見つけてくれた@Mouadに感謝します)。

于 2012-12-17T13:50:22.977 に答える
1

「+」演算子が結果の型に関して一貫して可換性を維持するように、Python 設計者はこの方法で加算を行ったと思います。type(a + b) == type(b + a)

誰もが 1 + 2 が 2 + 1 と同じ結果になることを期待しています。[1] + 'foo' は 'foo' + [1] と同じだと思いますか? はいの場合、結果はどうなりますか?

3 つの選択肢があります。左側のオペランドを結果の型として選択するか、右側のオペランドを結果の型として選択するか、エラーを発生させます。

+= には代入が含まれているため可換ではありません。この場合、左オペランドを結果の型として選択するか、スローします。ここで驚くべきは、それa += bが と同じではないということですa = a + ba += bは英語で「a を b に追加し、結果を a に代入する」に翻訳されません。「a を b にその場で追加する」と訳されます。そのため、文字列やタプルなどの不変オブジェクトでは機能しません。

コメントありがとうございます。投稿を編集しました。

于 2012-12-17T03:30:00.707 に答える
0

私の推測では、Python は強く型付けされており、ここで行うべき正しいことを明確に示すものはありません。Python に文字列自体を追加するように要求していますか、それとも文字列をリストにキャストするように要求していますか?

明示的は暗黙的よりも優れていることを忘れないでください。最も一般的なケースでは、これらの推測はどちらも正しくなく、意図しないことを誤って実行しようとしています。TypeError を発生させ、それを整理できるようにすることは、ここで行う最も安全で最も Pythonic な方法です。

于 2012-12-16T20:24:10.627 に答える