Pythonに++
および--
演算子がないのはなぜですか?
意味がないからではありません。 「x ++」を「x + = 1」と定義して、前の「xのバインディング」を評価することは完全に意味があります。
元の理由を知りたい場合は、古いPythonメーリングリストを調べるか、そこにいた人(例えばGuido)に尋ねる必要がありますが、事実を説明するのは簡単です。
他の言語のように単純な増分と減分は必要ありません。 Pythonでfor(int i = 0; i < 10; ++i)
のようなものを書くことはあまりありません。代わりにfor i in range(0, 10)
のようなことをします。
それほど頻繁には必要とされないので、それに独自の特別な構文を与える理由はずっと少なくなります。インクリメントする必要があるときは、+=
は通常は問題ありません。
意味があるかどうか、あるいは実行できるかどうかの決定ではありません。その利点が言語の中核的な構文に追加する価値があるかどうかという問題です。覚えておいて、これは4つの演算子 - postinc、postdec、preinc、predecであり、これらはそれぞれ独自のクラスオーバーロードを持つ必要があるでしょう。それらはすべて指定されテストされる必要があります。それは言語に命令コードを追加するでしょう(より大きく、そしてそれ故により遅く、VM engineを意味します)。論理的なインクリメントをサポートするすべてのクラスはそれらを実装する必要があるでしょう(+=
と-=
の上に)。
これはすべて+=
と-=
と重複しているため、純損失になります。
私が書いたこの元の答えは、コンピューティングの民間伝承からの神話です。 ACMの通信2012年7月 doi:10.1145/2209249.2209251
Cコンパイラーがあまり賢くなく、著者が機械語演算子を使用する直接的な意図を指定できるようにしたいときにCのインクリメント/デクリメント演算子が発明されました。するかもしれない
load memory
load 1
add
store memory
の代わりに
inc memory
pDP-11は、それぞれ*++p
および*p++
に対応する「autoincrement」および「autoincrement deferred」命令もサポートしていました。 マニュアル のセクション5.3を参照してください。
コンパイラーはCの構文に組み込まれた高度な最適化のトリックを処理するのに十分なほどスマートなので、構文上の利便性にすぎません。
Pythonにはアセンブラーを使用しないため、アセンブラーに意図を伝えるためのトリックはありません。
私はいつもそれがPythonの禅のこの行と関係があると思いました:
それを行うには、明白な方法が1つ(できれば1つだけ)あるべきです。
x ++とx + = 1はまったく同じことをするので、両方を持つ理由はありません。
もちろん、 "Guidoはちょうどそのように決めました"と言うこともできますが、問題はその決定の理由に関するものだと私は思います。いくつかの理由があると思います。
なぜならPythonでは、整数は不変だからです(intの+ =は実際には異なるオブジェクトを返します)。
また、++/ - では、前後のインクリメント/デクリメントについて心配する必要があり、x+=1
を書くのにもう1回キー入力するだけで済みます。言い換えれば、それはほとんど利益を犠牲にして潜在的な混乱を避けます。
Pythonはclarityに多く関わっており、その構造を持つ言語を学んでいない限り、--a
の意味を正しく推測するプログラマーはいないでしょう。
Pythonはミスを招く構造の回避についても多く、++
演算子は欠陥の豊富なソースであることが知られています。これらの2つの理由は、これらの演算子がPythonにないために十分です。
Pythonは、何らかの形式の開始/終了ブラケットや必須の終了マーキングなどの構文的手段ではなく、インデントを使用してブロックをマークするという決定は、主に同じ考慮事項に基づいています。
説明のために、2005年に条件演算子の導入に関する議論(C:cond ? resultif : resultelse
)をPythonに見てください。少なくとも 最初のメッセージ および 意思決定メッセージ の 議論 (以前に同じトピックに関するいくつかの先駆者がいた)。
雑学:その中で頻繁に言及されているPEPは「Python拡張機能の提案」です PEP 308 。 LCは リストの内包表記 を意味し、GEは ジェネレータ式 を意味します(そして、混乱しても心配する必要はありません。Pythonのいくつかの複雑なスポットではありません)。
それはちょうどそのように設計されました。インクリメント演算子とデクリメント演算子はx = x + 1
の単なるショートカットです。 Pythonは通常、操作を実行するための代替手段の数を減らす設計戦略を採用しています。 拡張代入 はPythonのインクリメント/デクリメント演算子に最も近いもので、Python 2.0まで追加されませんでした。
私はPythonにはとても慣れていませんが、その理由は言語内の可変オブジェクトと不変オブジェクトの間の強調が原因であると思います。さて、私はx ++がx = x + 1として容易に解釈されることができることを知っています、しかしそれはあなたがインプレースインプレースすることができるように見えます不変である。
私の推測では/感じていたり/お腹がすいただけです。
Pythonが++
演算子を持たない理由についての私の理解は以下の通りです。これをpython a=b=c=1
で書くと、同じオブジェクトを指す3つの変数(ラベル)が得られます(値は1です)。これを確認するには、オブジェクトメモリアドレスを返すid関数を使用します。
In [19]: id(a)
Out[19]: 34019256
In [20]: id(b)
Out[20]: 34019256
In [21]: id(c)
Out[21]: 34019256
3つの変数(ラベル)はすべて同じオブジェクトを指しています。変数の1つを増やして、それがメモリアドレスにどのように影響するかを見てください。
In [22] a = a + 1
In [23]: id(a)
Out[23]: 34019232
In [24]: id(b)
Out[24]: 34019256
In [25]: id(c)
Out[25]: 34019256
変数a
は、変数b
およびc
として別のオブジェクトを指していることがわかります。 a = a + 1
を使ったことは明らかです。言い換えれば、ラベルa
にまったく別のオブジェクトを割り当てます。 a++
を書くことができると想像してください。それはあなたが変数a
に新しいオブジェクトを代入したのではなく、古いものを増やしていくことを示唆するでしょう。これらすべてが混乱を最小限にするための私見です。よりよく理解するために、Python変数がどのように機能するかを見てください。
Pythonでは、ある関数が呼び出し側に認識されるようにいくつかの引数を変更できますが、別の引数には変更できないのはなぜですか?
まず、PythonはCによる間接的な影響のみを受けます。これは ABC の影響を強く受けます。 は明らかにこれらの演算子を持っていません なので、Pythonでそれらを見つけられないことも大きな驚きではないはずです。
次に、他の人が言っているように、インクリメントとデクリメントはすでに+=
と-=
によってサポートされています。
第3に、++
および--
演算子セットの完全サポートには通常、それらのプレフィックスバージョンとポストフィックスバージョンの両方のサポートが含まれます。 CとC++では、これは(私には)Pythonが採用する単純さと単純明快さの精神に反するように思われるあらゆる種類の「素敵な」構成要素につながる可能性があります。
例えば、C言語のステートメントwhile(*t++ = *s++);
は経験豊富なプログラマーにとっては単純でエレガントに思えるかもしれませんが、それを学ぶ人にとっては単純なものにすぎません。接頭辞と接尾辞の増減を混ぜて投げると、多くのプロでさえやめて少し考えなければならなくなるでしょう。
私はそれがPythonの信条 "明示的な方が暗黙的より優れている"から生じていると思います。
これは、 @ GlennMaynard が他の言語と比較して問題を検討しているためですが、Pythonでは、Pythonの方法で処理を行います。それは「なぜ」の質問ではありません。それはそこにあり、x+=
を使って同じ効果を得ることができます。 Pythonの禅 では、「問題を解決する方法は1つしかないはずです」と書かれています。複数の選択肢は芸術(表現の自由)には優れていますが、工学にはお粗末です。
++
クラスの演算子は副作用のある式です。これは一般にPythonには見られないものです。
同じ理由で、代入はPythonでは式ではないため、共通のif (a = f(...)) { /* using a here */ }
イディオムは使用できません。
最後に、そこにある演算子はPythonsの参照セマンティクスとあまり一致していないと思います。 Pythonには、C/C++から知られている意味を持つ変数(またはポインタ)はありません。
私はそれを理解したようにあなたはメモリの値が変更されるとは思わないでしょう。 cでx ++を実行すると、メモリ内のxの値が変わります。しかし、Pythonではすべての数値は不変なので、xが指し示していたアドレスにはまだx + 1ではなくxが含まれています。 x ++を書くとき、x changeは実際に起こることはx refrenceがx + 1が格納されているメモリ内の場所に変更されるか、doeが存在しない場合はこの場所を再作成することだと思うでしょう。
おそらくより良い質問は、これらの演算子がCに存在する理由を尋ねることでしょう。K&Rは、インクリメント演算子とデクリメント演算子を「普通ではない」と呼んでいます(2.8ページ46項)。序論ではそれらを「より簡潔で、より効率的」と呼んでいます。私は、これらの操作が常にポインタ操作に現れるという事実もそれらの導入の一部を演じたと思う。 Pythonでは、インクリメントを最適化しようとするのは無意味であると判断されています(実際にはCでテストしたところですが、gccで生成されたアセンブリは両方の場合でincludeではなくaddlを使用します)。ポインタ演算ですから、それはもう1つのやり方にすぎませんでした。Pythonがそれを悪用することはわかっています。
私はこれが古いスレッドであることを知っていますが、++ iの最も一般的なユースケースはカバーされていません。インデックスが提供されていないときに手動でセットにインデックスを付けることです。この状況がpythonがenumerate()を提供する理由です
例:任意の言語で、foreachのような構造を使用してセットを反復処理する場合-例のために、それは順序付けられていないセットであり、それらを区別するためにすべてに一意のインデックスが必要です
i = 0
stuff = {'a': 'b', 'c': 'd', 'e': 'f'}
uniquestuff = {}
for key, val in stuff.items() :
uniquestuff[key] = '{0}{1}'.format(val, i)
i += 1
このような場合、pythonは列挙メソッドを提供します。
for i, (key, val) in enumerate(stuff.items()) :
そのページですでに良い答えを完成させるには:
これを行うことにしたとしましょう。単項の+と - 演算子を壊すプレフィックス(++i
)。
今日、++
または--
の接頭辞は何もしません。これは、単項プラス演算子を2回有効にする(何もしない)または単項マイナス2回有効にする(2回:自分自身を取り消す)
>>> i=12
>>> ++i
12
>>> --i
12
それでそれは潜在的にその論理を壊すでしょう。