リファクタリングをPythonで実践!基本手法とコード例・注意点まで
Pythonといえば「AI・データサイエンス」と言われているほど、数学とPythonは切っても切れない関係になったといえます。
本記事では、Pythonで数学的な計算をする上で重要である「演算」、そしてその演算を行う「演算子」について解説します。
1. Pythonの演算子の種類
Pythonに限らず、プログラミング言語と「演算」は切っても切れない関係です。
演算とは、プログラムの中での計算を行うことを指しますが、
具体的には、四則演算や代入、比較といった処理が演算として定義されています。
そして、それらの演算を指示するための記号・記法が「演算子」と呼ばれるものです。
ここでは、Pythonにおける演算子を紹介します。
①算術演算子
算術演算子とは、一般的な算数などで行われる四則演算を指します。
まずは、どのプログラミング言語にも存在する四則演算から見ていきましょう。
# 加算
print(5 + 2) # -> 7
# 減算
print(5 - 2) # -> 3
# 乗算
print(5 * 2) # -> 10
# 除算
print(5 / 2) # -> 2.5
# 余り算
print(5 % 2) # -> 1
また、Pythonでは簡単に数値計算ができるような演算子が存在します。
# 除算結果の整数値
print(5 // 2) # -> 2
# べき乗の計算
print(5 ** 2) # -> 25
単純な四則演算以外にも柔軟に計算できるところがPythonの強みと言えるでしょう。
②代入演算子
次に、変数へ値を代入する「代入演算子」を紹介します。
「変数 = 代入する内容」で変数への代入が可能です。
val = 'Hello'
print(val) # -> Hello
文字列や数値だけでなく、先ほどの算術演算の計算結果も代入できます。
val = 5 ** 2
print(val) # -> 25
③比較演算子
ふたつの値を比較する際に使用するのが比較演算子です。
比較演算子を用いた比較結果はTrueまたはFalseとなるため、主にif文などの条件式内で利用します。
val = 12
# 数値が一致するか
print(val == 12) # -> True
# 数値が特定の値より大きいか
print(val > 10) # -> True
また、Pythonでは配列などの要素に対しても比較演算子を使用できます。
arr = ['Apple', 'Pine']
# 配列が一致するか
print(arr == ['Apple', 'Pine']) # -> True
# 配列内に「Apple」が存在するか
print('Apple' in arr) # -> True
# 配列内に「Grape」が存在するか
print('Grape' in arr) # -> False
比較演算子の種類
Pythonで使用できる比較演算子を紹介します。
演算子 | 記述例 | 説明 |
== | a == b | a と b は等しい |
!= | a != b | a と b は等しくない |
> | a > b | a は b より大きい |
< | a < b | a は b より小さい |
>= | a >= b | a は b 以下である |
<= | a <= b | a は b 以上である |
in | a in b | a が b に存在する |
not in | a not in b | a が b に存在しない |
④ブール演算子
ブール演算子は、「論理演算子」とも呼ばれており、ブール値(TrueまたはFalse)を用いて計算を行う演算子です。
また、ブール演算子による計算結果もブール値となります。
val1 = True
val2 = True
val3 = False
## 論理積(両方がTrueの場合はTrue)
print(val1 and val2) # -> True
print(val1 and val3) # -> False
## 論理和(どちらかがTrueの場合はTrue)
print(val1 or val2) # -> True
print(val1 or val3) # -> True
# 否定(逆の値)
print(not val1) # => False
また、ブール演算子は比較演算子と同様、if文の中で利用することが多い演算子です。
val1 = 10
val2 = 12
if val1 == 10 and val2 == 12:
print('特定の値です!')
この例の場合、比較演算子で比較した「val == 10」および「val == 12」の結果を、ブール演算子を用いて計算しています。
⑤ビット・シフト演算子
ビットとは、0または1で表現される値で、デジタル値の最小の値を指します。
Pythonをはじめとする多くのプログラミング言語では、数値をビットとして表現可能です。
このビットとして数値を表した数値を「2進数」と呼びます。
たとえば、「12」という数値は2進数(ビット)で表すと「1100」です。
シフト演算
この2進数で表現した値を「シフト」するのがシフト演算です。
数値をビットとして表した上で、その数値を右または左へシフトします。
例として、「右シフト」の例が以下の通りです。
00001100 -> 12
↓ 右に2シフトする
00000011 -> 3
今度は、「左」へシフトしてみましょう。
00001100 -> 12
↓ 左に2シフトする
00110000 -> 48
このシフトをPythonで実行するには、「>>」または「<<」を使用します。
# 12 を右へ2シフト
print(12 >> 2) # -> 3
# 12 を左へ2シフト
print(12 << 2) # -> 48
ビット演算
また、Pythonには数値をビットとして扱うことで、ビット単位で計算する機能を有しています。
前述の「ブール演算子」と同様の計算を全ての桁で実施するようなイメージでいましょう。
例として、9(1001)と5(101)で計算してみます。
論理積
1001 = 9
0101 = 5
-------
0001 = 1
論理和
1001 = 9
0101 = 5
-------
1101 = 13
この計算をPython上で実行してみましょう。
# 9と5の論理積
print(9 & 5) # -> 1
# 9と5の論理和
print(9 | 5) # -> 13
このように、ビット演算子を利用することでビット単位での数値計算が可能となります。
ビット・シフト演算子の種類
ビット演算とシフト演算の演算子の一覧を紹介します。
演算子 | 記述例 | 説明 |
& | a & b | a と b の論理積 |
| | a | b | a と b の論理和 |
^ | a ^ b | a と b の排他的論理和 |
<< | a << n | a をnビットぶん左シフト |
>> | a >> n | aをnビットぶん右シフト |
~ | ~a | a のビット反転 |
⑥文字列演算子
Pythonでは文字列を扱う際に「+」と「*」を利用できます。
どちらも文字列を結合して新しい文字列を生成します。
# +を利用して文字列を結合
print('Hello,' + 'World!') # -> Hello,World!
# *を利用することで、その文字を繰り返す
print('Hello,'*3) #-> Hello,Hello,Hello,
## 組み合わせて利用も可能
num = 3
print('Hello,'*3 + 'World!') # -> 'Hello,Hello,Hello,World!'
2. 演算子の優先順位
Pythonで利用できる演算子を紹介しましたが、これらの演算子には優先順位が存在します。
①算術演算子の優先順位
例えば、以下のような演算結果はどうなるのでしょうか?
print(5 + 4 * 2)
答えは、「13」です。
Pythonでは、通常の算数同様に加減算より乗除算が優先されるため、先に「4*2=8」が計算されます。
同様に、以下の計算も実施してみましょう。
print(5 + 6 * 4 ** 2)
答えは「101」です。この場合、以下のような計算が実行されています。
5 + 6 * 4 ** 2
= 5 + 6 * 16
= 6 + 95
= 101
このように、Pythonの算術には優先順位があるため、数学的な計算が可能です。
もちろん、以下のように括弧を使用することで優先して計算も可能です。
print((5 + 4) * 3);
この場合、括弧内の加算が先に計算されるため、答えは「27」となります。
②各種演算子の優先順位
算術演算子内での優先順位を紹介しましたが、他の演算子の優先順位も合わせて紹介します。
上記で紹介した演算子の優先順位は以下の通りです。
数字が小さいものほど優先度が高くなります。
- 括弧
- 算術演算子
- シフト演算子
- ビット演算子
- 比較演算子
- ブール演算子
例として、ビットシフトと算術演算子を組み合わせた場合を紹介します。
print(1 + 5 & 3 * 7 >> 1) # -> 2
この計算を順番に実施していきましょう。
まずは、2.算術演算が実行されます。
1 + 5 & 3 * 7 >> 1
↓ ↓
6 & 21 >> 1
次に、3.シフト演算が実行されます。
6 & 21 >> 1
↓ 21(10101)を右シフトすると10(1010)になる
6 & 10
最後に、4.ビット演算が実行されます。
6 & 10
↓ 6(0110)と10(1010)の論理積を計算すると2(0010)になる
2
このような計算が実行されて、計算結果が「2」となります。
演算の優先順位を覚えておくことでコードの量を減らせますが、
複数の演算を混ぜた際には想定と異なる計算順となる場合があります。
複雑な計算をしたい場合には、括弧を活用して計算順を分かりやすくするように心がけると良いでしょう。
3. 演算子のオーバーロード
Pythonでは、演算子を「オーバーロード」することで独自の演算を定義できます。
①オーバーロードとは?
オーバーロードとは、直訳すると「処理の追加」です。
オブジェクト指向における「オーバーロード」は、同じ名前のメソッドを複数定義することを指します。
異なる引数を用意することで、同名のメソッドであっても引数に応じて異なる処理を実装できます。
以下は、Javaで同名の複数メソッドを定義する例です。
public class TestClass {
// int(整数)を引数とするメソッド
public void register(int intValue) {
// 処理は省略
}
// String(文字列)を引数とするメソッド
public void register(String charValue) {
// 処理は省略
}
}
オーバーロードの詳しい説明は以下の記事を参照してみてください。
②特殊メソッドを使ってオーバーロード
Pythonでは、Javaのようなメソッドのオーバーロードを実装するには少しテクニックが必要ですが、演算子のオーバーロードを実装することで、各種演算子に対する処理を実装できます。
たとえば数字の場合、「+」といえば数字同士を足し算する演算子です。
Pythonには特殊メソッドが用意されており、その特殊メソッドを実装することで独自クラスに対する演算子の計算を定義できます。
例として、x座標とy座標を持つベクトルをあらわすクラスを作成してみましょう。
Pythonのクラス構文については、以下のサイトを参考にしてみてください。
class Vector:
x=0
y=0
def __init__(self, x, y):
self.x = x
self.y = y
def show(self):
print('(', self.x, ',', self.y, ')')
# 加算演算のオーバーロード
def __add__(self, other):
# xとyをそれぞれ加算したものを返却
return self.__class__(self.x + other.x, self.y + other.y)
# 2つの値を定義
v1 = Vector(5, 1)
v2 = Vector(6, 2)
# 足し算する
v3 = v1 + v2
v3.show() # -> ( 11, 3 )
今回はベクトルの和のみを実装しましたが、同様に演算のオーバーロードを実装することで対応する独自の計算を実現できます。
③特殊メソッドと対応する演算子
さいごに、特殊メソッドとそれに対応する演算子を紹介します。
対応する特殊メソッドを実装することでクラスを便利に使うことができますので、
計算を伴うクラスを作成する際には参考にしてみてください。
算術演算子
メソッド | 演算子 |
__add__ | + |
__sub__ | – |
__mul__ | * |
__truediv__ | / |
__floordiv__ | // |
__mod__ | % |
比較演算子
メソッド | 演算子 |
__eq__ | == |
__ne__ | != |
__lt__ | < |
__gt__ | > |
__le__ | <= |
__gt__ | >= |
ビット・シフト演算子
メソッド | 演算子 |
__and__ | & |
__or__ | | |
__xor__ | ^ |
__lshift__ | << |
__rshift__ | >> |
※掲載された社名、製品名は、各社の商標及び登録商標です。