[Python入門]Pythonの演算子まとめ:Python入門(2/2 ページ)
代入演算子/算術演算子/比較演算子/ブール演算子など、Pythonで各種の演算を行うための記号類をまとめる。
ブール演算子
ブール演算子は、複数の条件判断をつなげて「条件1かつ条件2」「条件1または条件2」といった複合的な判断を行ったり、ある条件の反転を行ったりする際に使われる。なお、not演算子は単項演算子である。
演算子 | 説明 | 例 |
---|---|---|
and | 条件が全て成立するかどうかを調べる | 'py' in 'python' and 'ub' in 'ruby'→True 'py' in 'Ruby' and 'py' in 'python'→False |
or | 条件のいずれかが成立するかどうかを調べる | 'py' in 'python' or 'ub' in 'python'→True 'ub' in 'python' or 'py' in 'ruby'→False |
not | 被演算子の真偽を反転する | not 'py' in 'python'→False not 'py' in 'ruby'→True |
ブール演算子 |
Pythonでは0や0.0などの数値、空の文字列やリストなどは偽(False)に見なされ、それ以外の値は真(True)と見なされることも覚えておこう。
print(not 1) # False
if not []:
print('empty list')
else:
print('not empty')
最後に、and演算子とor演算子は短絡評価される。「短絡評価」とは、最初の被演算子を評価した時点でその演算結果が決定できる場合に、それ以降の被演算子の評価を行わないという処理だ。例えば、「条件1 and 条件2」というブール演算を行う際に「条件1」の値がFalseと判断されると、「条件2」の値がTrueかFalseかによらず、この演算結果はFalseとなる。この場合には、「条件2」の値がどうかを調べる(評価する)ことはない。「条件1 or 条件2」であれば、「条件1」がTrueの時点で、この演算結果がTrueとなるので、同様に「条件2」の評価が行われないということだ。条件に既存の値を変更するような式を書いている場合には、注意が必要だ。
ビット演算子/シフト演算子
ビット演算子やシフト演算子は、整数値を2進数表現し、その各ビットに対して何らかの処理を施すものだ。以下の表にこれらをまとめる(以下の表の例では便宜的に8ビットの2進数表記をしている)。
演算子 | 説明 | 例 |
---|---|---|
& | ビット単位の論理積 | 10 & 5→0(10進数値「10」の2進数表現は「00001010」で、10進数値「5」の2進数表現は「00000101」であり、「1」と「1」の組み合わせになるビットがないので、その演算結果は「00000000」で10進数の「0」となる) |
| | ビット単位の論理和 | 10 | 5→15(10進数値「10」の2進数表現は「00001010」で、10進数値「5」の2進数表現は「00000101」であり、下位1〜4桁目のビットは「1」を含んだ組み合わせになるので、その演算結果は「00001111」で10進数の「15」となる) |
^ | ビット単位の排他的論理和 | 10 ^ 4→14(10進数値「10」の2進数表現は「00001010」で、10進数値「4」の2進数表現は「00000100」であり、下位2〜4桁目のビットが0と1の組み合わせとなり、その演算結果は「00001110」つまり10進数の「14」となる) |
~ | ビット反転 | ~0→-1(10進数値「0」を2進数で表現すると「00000000」となる。ビット反転すると、「11111111」となるが、これを10進数で表現すると「-1」となる) |
<< | 左シフト | 2 << 2→8(10進数値「2」の2進数表現は「00000010」であり、これを2ビットだけ左シフトすると「00001000」となる。これを10進数で表現すると「8」になる) |
>> | 右シフト | 32 >> 4→2(10進数値「32」の2進数表現は「00100000」であり、これを4ビットだけ右シフトすると「00000010」となるが、これは10進数で表現すると「2」になる) |
ビット演算子/シフト演算子 |
ビット単位の論理積/論理和/排他的論理和/反転というのは、2進数の0/1に対して次のような演算を行うものだ。
- ビット単位の論理積:2つのビットが共に1のときには、演算結果を1とする。1つでも0があれば、演算結果は0となる
- ビット単位の論理和:2つのビットが1つでも1のときには、演算結果を1とする。全てのビットが0のときに、演算結果は0となる
- ビット単位の排他的論理和:いずれかのビットが1、もう一方のビットが0のときに演算結果を1とする。両方のビットが1または0のときには、演算結果は0となる
- ビット反転:整数値の2進数表現の各ビットを0なら1に、1なら0にする
これを図にすると次のようになる。
1をTrue、0をFalseと見なした場合、ビット単位の論理積は、ブール演算子「and」と同様の演算であると考えられる。一方、ビット単位の論理和は、ブール演算子「or」と同様の演算であると考えられる。
一方、シフト演算子「<<」と「>>」は共に整数を被演算子に取り、左側の被演算子の2進数表現を、右側の被演算子に与えたビット数だけ、左もしくは右にシフトする。なお、nビットだけ左にシフトするのは、元の数値の2n倍を計算する処理に、nビットだけ右にシフトするのは、元の数値の2-n倍を計算する処理となる。例えば、以下は「10 << 2」の演算の様子だ。
幾つかの例を以下に示す(実行結果は省略)。
x = 39 # 2進数で00100111
y = 142 # 2進数で10001110
print(x & y) # 6
print(x | y) # 175
print(x ^ y) # 169
print(x << 2) # 156
print(y >> 1) # 71
三項演算子
三項演算子は「条件式」とも呼ばれるもので、式中に「条件に応じて決まる値」を記述するのに使える。
その書式は「値1 if 条件 else 値2」であり、「条件」が成立したときには「値1」が、成立しなかったときには「値2」が演算結果となる。
以下に例を示す(実行結果は省略)。
from random import randint
number = randint(1, 10)
message = 'even' if number % 2 == 0 else 'odd'
print(f'{number} is {message} number')
三項演算子はネストさせることも可能だ。以下はFizzBuzz判定を三項演算子を用いて記述したものだ。
from random import randint
number = randint(1, 30)
message = 'fizzbuzz' if number % 3 == 0 and number % 5 == 0 \
else 'fizz' if number % 3 == 0 \
else 'buzz' if number % 5 == 0 \
else str(number)
print(f'{number}: {message}')
簡単なものであれば、三項演算子を使ってもよいが、ここまで複雑なものは素直に関数やif文を使って書くのがよいだろう。
セイウチ演算子(代入式)
Pythonでは一般に、何かの変数に値を代入するには上で見た代入文(代入演算子)が使われる。これは文であり式ではない。そのため、式しか書けないところでは変数に値を代入できない。だが、式しか書けないところで変数への代入ができると便利だったり、コードがきれいに書けたり、効率的だったりすることがある。
代入式は「変数 := 式」のように書く。等号「=」の前にコロン「:」がある点に注意しよう。基本的には、式を書けるところには代入式を書けるが、コードがあいまいになったり、コードを読む人が困惑したりすることがないように、代入式を書くことが許されていない箇所もある(後述)。
簡単な例としてif文の条件に代入式を使ってみよう。以下は、文字列sの長さを調べて、5文字よりも多い場合とそうでない場合で処理を分けて、メッセージを表示するコードだ。
s = 'foo'
if len(s) > 5:
print(f'length of {s}: {len(s)} ( > 5)')
else:
print(f'length of {s}: {len(s)} ( <= 5)')
これを実行すると、if文の条件とメッセージの表示とでlen関数の呼び出しが複数回行わる。同じ結果を得るために、同じ関数を何度も呼び出すのは効率がよくない(し、スッキリともしない)。これを避けるには、if文の前でlen関数を呼び出して、その値を変数に代入しておくことが考えられる。
s = 'foo'
n = len(s)
if n > 5:
print(f'length of {s}: {n} ( > 5)')
else:
print(f'length of {s}: {n} ( <= 5)')
これでlen関数の呼び出しが複数回行われることはなくなったが、代入式を使えば、上のコードはより簡潔に書ける。
s = 'foo'
if (n := len(s)) > 5:
print(f'length of {s}: {n} ( > 5)')
else:
print(f'length of {s}: {n} ( <= 5)')
注意が必要なのは、代入式の優先順位が演算子の中で一番低くなっている点だ。そのため、上のコード例では「(n := len(s))」と代入式全体をかっこでくくっている。代入式を囲むかっこがないと、「n := len(s) > 5」の「len(s) > 5」の結果が変数nに代入されてしまう(この場合、文字列sは'foo'であり、3文字なので「len(s) > 5」の値であるfalseが変数nに代入される)。
もう1つ例を示す。これはリストnumbersの要素とそれをsomefunc関数に渡して得られた結果をタプルとするリストを作成する。ただし、somefunc関数が返した結果が5より大きい場合にのみ、タプルを新しく作成するリストの要素としている。
numbers = [0, 1, 2, 3, 4]
def somefunc(x):
return x * 2
l = [(x, somefunc(x)) for x in numbers if somefunc(x) > 5]
print(l) # [(3, 6), (4, 8)]
ここでもsomefunc関数が複数回呼び出されている。このようなところでは代入式が使える。
numbers = [0, 1, 2, 3, 4]
def somefunc(x):
return x * 2
l = [(x, y) for x in numbers if (y := somefunc(x)) > 5]
print(l) # [(3, 6), (4, 8)]
この場合、代入式を書くのがif句となっている点に注意しよう。こちらの方が先に評価され、その結果がタプル内のyとなる。
代入式は書くところを間違えなければ、コードをシンプルにしてくれる。しかし、コードがあいまいになったり、コードを読む人が困惑したりすることがないように、代入式を書けないところもある。例えば、式は文が書ける位置に記述できるが(式文)、代入式はそうはできない。
y := 1 # SyntaxError
ただし、かっこで代入式を囲むことで代入式を式文として記述することは可能だ。
(y := 1) # OK
詳しくはPEP 572の該当箇所を参照されたい。
演算子の優先順位
最後に演算子の優先順位を以下にまとめる。表で上にあるものほど、高い優先度を持つ。
優先順位 | 演算子 | 説明/備考 |
---|---|---|
1 | ** | べき乗演算子。左の単項演算子よりも優先度が高いが、右の単項演算子よりも優先度が低くなる |
2 | 単項+、単項-、単項~ | 単項+は被演算子の符号をそのままとする。単項-は被演算子の符号を反転する。単項~は被演算子のビット反転を行う |
3 | *、/、//、% | 乗算/除算を行う |
4 | +、- | 加算/減算を行う |
5 | <<、>> | ビットシフトを行う |
6 | & | ビット単位の論理積 |
7 | ^ | ビット単位の排他的論理和 |
8 | | | ビット単位の論理和 |
9 | in、not in、is、is not、<、<=、>、>=、==、!= | 比較演算子 |
10 | 単項not | 被演算子の真偽を反転する |
11 | and | 条件1「かつ」条件2を調べる |
12 | or | 条件1「または」条件2を調べる |
13 | 三項演算子 | 条件に応じて値を決定する |
14 | セイウチ演算子 | 式しか書けないところで、変数に値を代入する |
演算子の優先順位 |
まとめ
今回のまとめ:Pythonの演算子
- 演算子には、代入演算子/累算代入演算子/算術演算子/比較演算子/ブール演算子/ビット演算子/シフト演算子/三項演算子などの種類がある
- 算術演算子は数値同士の加減乗除やべき乗、商と剰余などが求められる。また、一部の演算子ではシーケンス(文字列やリストなど)の結合や繰り返しが得られる
- 比較演算子を使うと、オブジェクトの同一性、等価性、大小比較、存在確認などを行える
- ブール演算子は、複数の条件をつなげたり、特定の条件の真偽を反転したりするのに使用できる
- ビット演算子/シフト演算子は、整数の2進数表現に対して、ビット単位で論理積/論理和/排他的論理和/ビット反転を求めたり、指定したビット数だけ左右にシフトしたりする
- 三項演算子は「条件式」とも呼ばれ、指定した条件が成立したときと、成立しなかったときとで異なる値を演算結果とする。if文と異なり、式中に記述できる
- 演算子には優先順位があり、多くの場合は直感的な順序で演算が行われるが、そうではないときもある。演算の順位を明確にしたり、優先度を異なるものにしたりしたいときにはかっこ「()」を使用する
「Python入門」
Copyright© Digital Advantage Corp. All Rights Reserved.