Pythonに++および-演算子がないのはなぜですか?


回答:


443

それが意味をなさないからではありません。「x ++」を「x + = 1」として定義することは完全に理にかなっています。以前のxのバインディングに評価されます。

元の理由を知りたい場合は、古いPythonメーリングリストを確認するか、そこにいた人に尋ねる必要があります(たとえば、Guido)。しかし、事実を正当化するのは簡単です。

単純な増分と減分は、他の言語ほど必要ではありません。for(int i = 0; i < 10; ++i)Pythonのように書くことはあまりありません。代わりにあなたは次のようなことをしますfor i in range(0, 10)

ほとんど必要とされないので、独自の特別な構文を与える理由ははるかに少ないです。インクリメントする必要がある場合、+=通常は問題ありません。

それが理にかなっているのか、それが実行できるのかという決定ではありません。言語のコア構文に利点を追加する価値があるかどうかという問題です。これは4つの演算子(postinc、postdec、preinc、predec)であることを思い出してください。これらはそれぞれ独自のクラスオーバーロードを持つ必要があります。それらはすべて指定してテストする必要があります。それは言語にオペコードを追加します(より大きく、したがってより遅いVMエンジンを意味します)。論理インクリメントをサポートするすべてのクラスは、それらを実装する必要があります(+=およびの上に-=)。

これは+=および-=ですべて冗長なので、正味の損失になります。


98
+ [/-]で整然と行われていないarray [i ++]のようなものを使用すると便利なことがよくあります。
ターナーヘイズ

102
@thayes:これはPythonでは一般的なパターンではありません。
Glenn Maynard、

9
@thayesこれはループ内にあるため、i直接ループすることもできます-実際にそれが必要で、たとえば使用するだけではできない場合array.append()
Tobias Kienzler

31
私は読みやすさと予測可能性にもっと大きな懸念があると思います。戻る私のCの日で、私はより多くの区別についての誤解に起因する十分なバグを見たi++++i...
チャールズダフィー

5
事後正当化に追加:、私が遭遇した上で、プロジェクトのI仕事上での問題からC ++コードの苦しみの公正な量(より多くの誰もが自分の生活の中で必要以上)++および--方法で使用されている未定義または未指定で結果その動作。これにより、複雑で正確に解析するのが難しいコードを書くことができます。
Brian Vandenberg

84

私が書いたこの最初の回答は、コンピューティングの民間伝承からの神話です。ACMコミュニケーションの編集者への手紙に記載されているように、「歴史的に不可能」であるとデニスリッチーによって明らかにされました 2012年7月doi:10.1145 / 2209249.2209251


Cのインクリメント/デクリメント演算子は、Cコンパイラがあまり賢くないときに発明され、著者は、機械語演算子を使用する必要があるという直接的な意図を指定できるようにしたかったため、するかもしれない

load memory
load 1
add
store memory

の代わりに

inc memory 

PDP-11は、それぞれ*++p*p++に対応する「自動インクリメント」および「自動インクリメント遅延」命令もサポートしていました。ひどく気になる場合は、マニュアルのセクション5.3を参照してください。

コンパイラーは、Cの構文に組み込まれた高度な最適化トリックを処理するのに十分スマートであるので、それらは現在、構文上の便宜にすぎません。

Pythonはアセンブラを使用しないため、アセンブラに意図を伝えるトリックはありません。


4
Javascriptには++があります。それは「アセンブラーに意図を伝えるトリック」ではないと思います。さらに、Pythonにはバイトコードがあります。理由は何か他にあると思います。
Nathan Davis

13
この「コンパイラにヒントを提供する」ビジネスは、まさに神話です。率直に言って、これはどの言語にもばかげた追加であり、次の2つの原則に違反しています。 そして2.あなたは有能なエンジニアが読むためにコード化しません、あなたは有能なエンジニアが午前3時に疲れきってカフェインに飛び乗っている間に読むためにコード化します。

3
@ tgm1024公平を期すために、毎秒10〜30文字の半二重テレタイプでコーディングする場合は、来週までにキー入力できるようにコーディングします。
msw 2015年

4
@ tgm1024 UnixとCは、ユーザー通信に信じられないほど遅いテレタイプを使用するPDP-11での初期の開発の大部分を見ました。今日のマシンのコーディングはほとんどばかげていることは間違いありませんが、当時はボトルネックとなったのはヒューマン/マシンインターフェースでした。あなたがしなければならなかったとしても、ゆっくりと働くことを想像するのは難しいです。
msw 2015年

65

私はいつもそれがpythonのzenのこの行と関係があると思っていました:

それを行うには明白な方法が1つ(できれば1つだけ)あるはずです。

x ++とx + = 1はまったく同じことを行うので、両方を持つ必要はありません。


10
one--ゼロですか?
Andre Holzner、2013年

25
one--文中では1ですが、直後は0です。したがって、この「公理」は、インクリメント/デクリメント演算子が自明ではないことも示唆しています。
ビクターK

14
@EralpB + =を削除すると、x + = 10のようなことはできなくなります。+ =は、++のより一般的なケースです
Rory

8
また、「明示的は暗黙的よりも優れています」。
Ber

2
x + = 1は式ではないため、まったく同じではありません。これはステートメントであり、何にも評価されません。次のようなことはできません: 'row [col ++] = a; row [col ++] = b '。c ++が持っているpre-incとpost-incについては言うまでもありません。
2014

38

もちろん、「ガイドはそのように決断した」と言えるかもしれませんが、問題はその決断の理由にあると思います。私はいくつかの理由があると思います:

  • ステートメントと式が混在するため、これは良い方法ではありません。http://norvig.com/python-iaq.htmlを参照してください
  • 一般的に、読みにくいコードを書くことを奨励します
  • 既に述べたように、Pythonでは不要な、言語実装の追加の複雑さ

12
誰かがようやくステートメントと表現の側面について言及してくれてうれしい。Cでは代入は式なので、++演算子です。Pythonの割り当てではそう、声明であれば、それは++を持っていた、それはおそらくあまりにも(とさえあまり有用または必要に応じて)、代入文である必要があります。
martineau

同意-それらがステートメントである場合、最低でも、ポスト演算子とプリ演算子の違いについて話すことは絶対に無意味になります。
Crowman 2013

17

Pythonでは、整数は不変であるためです(intの+ =は実際には別のオブジェクトを返します)。

また、++ /-を使用すると、プリインクリメント/ポストインクリメント/デクリメントを心配する必要があり、書くのにもう1回のキーストロークだけで済みますx+=1。言い換えれば、ほとんど利益を犠牲にすることなく、潜在的な混乱を回避します。


intもCでは不変です。そう思わない場合は、Cコンパイラでコードを生成してみてください42++...このような(リテラル定数の変更)、一部の古いFortranコンパイラで実際に可能でした(または私が読んだ):すべての将来の使用そのプログラム実行でのそのリテラルの実際には異なる値になります。幸せなデバッグ!
Lutz Prechelt、2015年

10
正しい。42はリテラル定数です。定数は不変です(または少なくともそうである必要があります)。これはint、一般的なC が不変であるという意味ではありません。intC のinは、単にメモリ内の場所を示します。そして、その場所のビットは非常に可変です。たとえば、の参照を作成し、intその参照のリファレントを変更できます。この変更はint、その場所へのすべての参照(元の変数を含む)に表示されます。同じことがPython整数オブジェクトにも当てはまりません。
Nathan Davis

x + = 1がinc memになることはありません。Pythonは関数呼び出しを実行して、変数に1を追加します。それは哀れです。
PalaDolphin、2018

12

明快さ!

Pythonは明確さを重視しているため、プログラマーが--aその構造を持つ言語を学んでいない限り、その意味を正しく推測することはできません。

Pythonはまた、間違いを招く構成を回避することを重視しており、++演算子は欠陥の豊富な原因であることが知られています。これらの2つの理由は、Pythonでこれらの演算子を使用しないために十分です。

Pythonが何らかの形式の開始/終了ブラケットや必須の終了マークなどの構文的手段ではなく、インデントを使用してブロックをマークするという決定は、主に同じ考慮事項に基づいています。

例として、2005年にPythonに条件演算子(C:でcond ? resultif : resultelse)を導入することに関するディスカッションを見てください。少なくとも、そのディスカッション最初のメッセージ決定メッセージ(以前に同じトピックに関するいくつかの前兆があった)を読んでください。

雑学: ここで頻繁に言及されるPEPは、「Python拡張提案」PEP 308です。LCはリスト内包表記を意味し、GEはジェネレーター式を意味します(混乱させても心配しないでください。Pythonのいくつかの複雑なスポットではありません)。


10

pythonに++演算子がない理由についての私の理解は次のとおりです。これをpythonで記述a=b=c=1すると、同じオブジェクト(値は1)を指す3つの変数(ラベル)が表示されます。これは、オブジェクトのメモリアドレスを返す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ので、それは明確に明らかです。つまり、labelに完全に別のオブジェクトを割り当てますa。あなたがa++それを書くことができると想像してください、あなたは可変のa新しいオブジェクトに割り当てなかったが古いオブジェクトをラッターインクリメントすることを示唆するでしょう。これらはすべて、混乱を最小限に抑えるための私見です。理解を深めるには、Python変数の仕組みをご覧ください。

Pythonでは、なぜ関数は呼び出し元が認識しているように一部の引数を変更でき、他の引数は変更できないのですか?

Pythonは値による呼び出しですか、それとも参照による呼び出しですか?どちらでもない。

Pythonは値渡しですか、それとも参照渡しですか?

Pythonは参照渡しですか、値渡しですか?

Python:変数を参照渡しするにはどうすればよいですか?

Python変数とメモリ管理について

Pythonでの値渡し動作のエミュレート

参照によるPython関数呼び出し

Pythonのようなコード:慣用的なPython


9

そのように設計されただけです。インクリメント演算子とデクリメント演算子は、の単なるショートカットですx = x + 1。Pythonは通常、操作を実行する代替手段の数を減らす設計戦略を採用しています。 拡張代入は、Pythonのインクリメント/デクリメント演算子に最も近いものであり、Python 2.0まで追加されていませんでした。


3
うんあなたは置き換えることができ、同様に、チームメイトreturn a[i++]return a[i=i+1]
ルイス・デ・スーザ

7

私はPythonに非常に慣れていませんが、その理由は、言語内の可変オブジェクトと不変オブジェクトが強調されているためだと思います。さて、x ++はx = x + 1として簡単に解釈できることを知っていますが、不変である可能性のあるオブジェクトをインプレースでインクリメントているように見えます。

ただ私の推測/感情/勘です。


この態様では、x++近い方にあるx += 1よりもx = x + 1、これらの二つの可変オブジェクトにも差を作ります。
glglgl 2012

4

まず、PythonはCの間接的な影響のみを受けます。ABCの影響を強く受けているため、ABCはこれらの演算子がないようです。そのため、Pythonでこれらの演算子を見つけなくても、驚くことではありません。

第二に、他の人が言ったように、増加と減少はすでにサポートされ+=-=います。

3番目に、++and --演算子セットの完全サポートには、通常、それらのプレフィックスバージョンとポストフィックスバージョンの両方のサポートが含まれます。CおよびC ++では、これは、Pythonが採用する単純性および単純性の精神に(私には)反するように思われるあらゆる種類の「素敵な」構成につながる可能性があります。

たとえば、Cステートメントwhile(*t++ = *s++);は、経験豊富なプログラマにとっては単純でエレガントに見えるかもしれませんが、それを学んでいる人にとっては単純ではありません。プレフィックスとポストフィックスのインクリメントとデクリメントを組み合わせて投入します。多くのプロでさえ、少し立ち止まって考える必要があります。


3

私は、「明示的なものは暗黙的なものよりも優れている」というPythonの信条に基づいていると思います。


まあ、あなたはPythonで明示的に「begin」と「end」ステートメントを書かないでしょ?私は声明に同意しますが、それには限界があると思います。私たちはその境界について議論することはできますが、私たち全員が同意することはできると思います。そして、その決定には非常に多くの意見と正当化があるため、私はそれが明確な選択だったとは思いません。少なくとも、明記されているソースは見つかりません
Hasan Ammori

3

これは、@ GlennMaynardが他の言語と比較して問題を検討しているためかもしれませんが、Pythonでは、Pythonの方法で物事を行います。「なぜ」の質問ではありません。そこにあり、と同じ効果を得ることができますx+=Pythonの禅、与えられている:「のみの問題を解決する一つの方法があるはずです。」複数の選択肢は、芸術(表現の自由)には優れていますが、エンジニアリングには粗末です。


2

++演算子のクラスは、副作用のある式です。これは一般的にPythonにはないものです。

同じ理由で、割り当てはPythonの式ではないため、一般的なif (a = f(...)) { /* using a here */ }イディオムは使用できません。

最後に、私はthere演算子がPythonの参照セマンティクスとあまり一致していないと思います。Pythonには、C / C ++から既知のセマンティクスを持つ変数(またはポインター)がないことに注意してください。


1
テスト/式/リスト内包表記で副作用のある関数を呼び出すことを妨げるものはありません。f(a)ここaで、はリストであり、いくつかの不変オブジェクトです。
ジャン=フランソワ・ファーブル

1

たぶん、もっと良い質問は、なぜこれらの演算子がCに存在するのかを尋ねることでしょう。K&Rはインクリメント演算子とデクリメント演算子を「異常」と呼んでいます(セクション2.8ページ46)。序文では、それらを「より簡潔で、多くの場合より効率的」と呼んでいます。これらの操作が常にポインタ操作で発生するという事実も、それらの導入に一役買ったと思います。Pythonでは、インクリメントを最適化しようとしても意味がないと判断されていると思います(実際、Cでテストを行っただけで、gccで生成されたアセンブリはどちらの場合もinclではなくaddlを使用しているようです)。ポインタ演算; したがって、それはもう1つの方法であり、Pythonはそれを嫌っています。


1

私が理解したように、メモリの値が変更されたとは思わないでしょう。cでx ++を実行すると、メモリ内のxの値が変化します。しかし、Pythonではすべての数値が不変であるため、xが指しているアドレスには、x + 1ではなくxがあります。x ++を書くとき、xが実際に何が起こるかは、xの屈折がx + 1が格納されているメモリ内の場所に変更されるか、doeが存在しない場合はこの場所を再作成すると考えられます。


1
それで、これ++と何が違うの+= 1ですか?
2014

1

そのページですでに良い回答を完了するには:

これを行うことにしたとしましょう++i。単項の+演算子と-演算子を壊すプレフィックス()です。

今日では、単項プラス演算子を2回(何もしない)または単項マイナス2回(2回:自分自身をキャンセル)できるため、プレフィックスを付ける++--、何もしません。

>>> i=12
>>> ++i
12
>>> --i
12

そのため、そのロジックが壊れる可能性があります。


1

他の回答では、イテレーターに必要ない理由を説明していますが、インラインで変数を増やすように割り当てる場合に役立つ場合があります。タプルと複数の割り当てを使用して同じ効果を得ることができます。

b = ++a になる:

a,b = (a+1,)*2

b = a++なる:

a,b = a+1, a

Python 3.8では代入:=演算子が導入されておりfoo(++a)

foo(a:=a+1)

foo(a++) まだとらえどころのないです。


2
:=割り当ては不名誉です
ネヘム

0

これはオブジェクトの可変性と不変性の概念に関連していると思います。2,3,4,5はPythonでは不変です。下の画像を参照してください。2は、このpythonプロセスまでのIDを修正しました。

定数と変数のID

x ++は本質的にCのようなインプレース増分を意味します。Cでは、x ++はインプレース増分を実行します。したがって、x = 3であり、x ++はメモリ内の3を4にインクリメントします。Pythonがメモリ内に3がまだ存在する場合とは異なります。

したがって、Pythonでは、メモリに値を再作成する必要はありません。これにより、パフォーマンスが最適化される可能性があります。

これは直感に基づく答えです。


0

私はこれが古いスレッドであることを知っていますが、++ 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()) :
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.