Last Updated: 2/6/2024, 5:44:57 AM
# 3. ベタ書きと関数呼び出し
ベタ書きの方が速い
Python は関数やメソッドの呼び出しコストが結構大きいので、 内部で何度も呼び出されている関数を単純にベタ書きするだけで、 処理速度が少し速くなったりします。 cProfile で cumtime が大きかった時の対処法の1つです。
# 3.1. max 関数の書き換え
4, 5 倍速くなる。
# 比較対象
max(2, 1)
2 if 2 > 1 else 1
# 測定結果
# ベタ書きのコード
python -m timeit -n 1000 "max(2, 1)"
# 関数を使ったコード
python -m timeit -n 1000 "2 if 2 > 1 else 1"
$ # ベタ書きのコード
$ python -m timeit -n 1000 "max(2, 1)"
1000 loops, best of 3: 0.234 usec per loop
$ # 関数を使ったコード
$ python -m timeit -n 1000 "2 if 2 > 1 else 1"
1000 loops, best of 3: 0.0379 usec per loop
# 補足
ちなみに三項演算子では「定数畳み込み」はされない。
import dis
dis.dis("2 if 2 > 1 else 1")
>>> import dis
>>> dis.dis("2 if 2 > 1 else 1")
1 0 LOAD_CONST 0 (2)
2 LOAD_CONST 1 (1)
4 COMPARE_OP 4 (>)
6 POP_JUMP_IF_FALSE 12
8 LOAD_CONST 0 (2)
10 RETURN_VALUE
>> 12 LOAD_CONST 1 (1)
14 RETURN_VALUE
>>>
# 3.2. 切り捨て
4, 5 倍速くなる。
# 比較対象
4 // 3
math.floor(4 / 3)
int(4 / 3)
# 測定結果
python -m timeit -s "a, b = 4, 3" "a // b"
python -m timeit -s "a, b = 4, 3" "int(a / b)"
python -m timeit -s "a, b = 4, 3; import math" "math.floor(a / b)"
$ python -m timeit -s "a, b = 4, 3" "a // b"
10000000 loops, best of 5: 35.6 nsec per loop
$ python -m timeit -s "a, b = 3, 3" "int(a / b)"
2000000 loops, best of 5: 172 nsec per loop
$ python -m timeit -s "a, b = 4, 3; import math" "math.floor(a / b)"
2000000 loops, best of 5: 163 nsec per loop
$
# 補足
4 / 3
, 4 // 3
には、定数畳み込みが走るので
-s
オプションで変数に代入している。
# 3.3. 組み込み関数 divmod の書き換え
# 比較対象
c, d = 4//3, 4%3
c, d = divmod(4, 3)
# 測定結果
python3 -m timeit -s "a,b=5,3" "divmod(a, b)"
python3 -m timeit -s "a,b=5,3" "a//b"
$ python3 -m timeit -s "a,b=5,3" "divmod(a, b)"
2000000 loops, best of 5: 127 nsec per loop
$ python3 -m timeit -s "a,b=5,3" "a//b"
10000000 loops, best of 5: 35.3 nsec per loop
$
# 補足
3.2, 3.3 については「暗黙の型変換」を題材に記事を書きました。