Pythonにインクリメント・デクリメント演算子はない?その理由と正しい使い方
Pythonにインクリメント・デクリメント演算子は存在しない
Pythonには、C言語などでおなじみの単項インクリメント演算子(++)やデクリメント演算子(--)が用意されていません。代わりに、値を1つ増やす場合は a += 1 を、1つ減らす場合は a -= 1 を使用します。
a += 1 # 値を1増やす(インクリメント)
a -= 1 # 値を1減らす(デクリメント)
これはPythonの設計思想によるものです。「同じことを実現する方法は1つに絞る」というZen of Python(Pythonの禅)の原則に沿い、複数の記法をあえて許容していません。
基本的な使用例
>>> a = 0
>>>
>>> # インクリメント
>>> a += 1
>>>
>>> # デクリメント
>>> a -= 1
>>>
>>> # a の値を確認
>>> a
0
C経験者が注意すべき点:「変数」ではなく「名前とオブジェクト」
C言語などの経験がある方は特に注意が必要です。PythonにはC言語のような意味での「変数」は存在せず、「名前(name)」と「オブジェクト(object)」という仕組みを採用しています。さらに、Pythonの整数型(int)はイミュータブル(変更不可能)です。
具体例で確認してみましょう。
>>> a = 1
>>> print(id(a))
1919375088
>>> print(hex(id(a)))
0x726756f0
このコードが意味するところは次のとおりです。まず、値が1であるint型のオブジェクトを生成し、それに「a」という名前を付けています。オブジェクトは値1を持つintのインスタンスであり、名前aはそのオブジェクトを参照します。重要なのは、割り当てられた名前aと、その参照先のオブジェクトは別物であるという点です。
a += 1 を実行すると何が起きるのか
次に、aをインクリメントしてみます。
>>> a += 1
>>> print(id(a))
1919375104
>>> print(hex(id(a)))
0x72675700
idが変化していることに注目してください。intはイミュータブルなため、Pythonは上記の文を内部的に次の手順で処理します。
- 名前aが参照するオブジェクトを探す(id が 0x726756f0 の int)
- そのオブジェクトの値を取得する(値は1)
- その値に1を加える(1 + 1 = 2)
- 値2を持つ新しいintオブジェクトを生成する(id が 0x72675700 のオブジェクト)
- 名前aを新しいオブジェクト(0x72675700)へ再バインドする
- 以降、aは新しいオブジェクトを参照し、以前のオブジェクト(0x726756f0)は名前aから参照されなくなる。他に参照する名前がなければ、後ほどガベージコレクションによって回収される
つまり、a += 1 は「aをa+1に再代入する」処理です。これは厳密にはインクリメント演算子ではありません。a自体を「増加」させているのではなく、新しいオブジェクトへの再代入を行っているためです。
複数の名前が同じオブジェクトを参照する例
この仕組みは、複数の名前を使った例でも確認できます。
>>> a = b = c = 1
>>> id(a)
1919375088
>>> id(b)
1919375088
>>> id(c)
1919375088
>>> # 上記3つはすべて同じid
>>>
>>> # ここで a をインクリメント
>>> a += 1
>>> id(a)
1919375104
>>> id(b)
1919375088
>>> id(c)
1919375088
この結果から、最初はa、b、cの3つの名前がすべて同一のオブジェクト(id 1919375088 のint)を参照していたことがわかります。しかし、aをインクリメントすると、aだけが新しいオブジェクト(id 1919375104)へ再代入され、bとcは引き続き元のオブジェクト(1919375088)を参照したままになります。もしCのように値そのものが書き換わる仕組みであれば、bとcも影響を受けるはずです。これこそが「名前とオブジェクト」「イミュータビリティ」というPythonの挙動を示す好例です。
++ や -- と書くとどうなる?
実は、Pythonで ++a や --a と書いても構文エラーにはなりません。ただし、これらはインクリメント・デクリメントとして機能するわけではありません。
>>> a = 1
>>> ++a
1
>>> --a
1
++a は「単項プラスを2回適用した +(+a)」、--a は「単項マイナスを2回適用した −(−a)」と解釈されるためです。結果として値はまったく変わらず、意図した動作にはならないため注意しましょう。
まとめ
- Pythonには
++/--演算子は存在せず、代わりにa += 1/a -= 1を使う - Pythonの変数は「名前とオブジェクト」の仕組みで、整数(int)はイミュータブル
a += 1はaを増加させるのではなく、新しいオブジェクトへの再代入である++a/--aはエラーにならないものの、単項演算子の重ね掛けとして解釈されるだけで値は変わらない
-
Pythonで++や--演算子が使えない理由と正しい代替方法
Pythonでは++演算子が使えない C言語、C++、Javaなどの多くのプログラミング言語では、「++」および「--」演算子を使って変数の値を1ずつ増加・減少させることができます。しかし、Pythonにはこれらのインクリメント・デクリメント演算子は存在しません。 なぜ++演算子は動作しないのか その理由は、Pythonの変数の仕組みにあります。Pythonにおいて、変数とはメモリ上のオブジェクトに対する「ラベル(名札)」にすぎません。さらに、Pythonの数値オブジェクトはイミュータブル(不変)です。 したがって、a = 10 の状態で「a++」と書くと、これはオブジェクト「10」自体の値
-
【Python入門】eval()関数で文字列を評価してオブジェクトを取得する方法
Pythonには、文字列を引数として受け取り、それをPythonの式として評価する組み込み関数 eval() が用意されています。インタプリタは渡された文字列を有効なPython式として解析し、正しければ評価を実行した結果のオブジェクトを返します。eval()関数の基本的な使い方eval() の構文は以下のとおりです。eval(expression[, globals[, locals]])第一引数には評価対象の文字列を指定します。省略可能な第二・第三引数では、評価時に使用するグローバルおよびローカルの名前空間(辞書)を指定できます。算術式を含む文字列の評価最もシンプルな例が、算術式を含む文字