はじめに
ChatGPTはプログラミングに関して高い能力を発揮しているそうなので、自分もテストしてみました。
今回取り扱う書籍は以下のEffective Pythonです。
Effective PythonはPython中級者から上級者が対象の書籍で、使いやすく理解しやすいテクニック(一部はかなりマニアック)が紹介されています。
この記事はChatGPTに敬意を示しつつも、今回は効率の良い実用的なPythonのプログラムを書くことができるかどうかを調べる目的で作成しています。
少しでも参考になれば幸いです!
関数のプログラム
2変数徐算する関数(項目20)
まず2変数を徐算する関数の作成を指示したら以下の関数が出力されました。
def divide_numbers(num1, num2):
return num1 / num2
この関数は、num2=0
の時にエラーを吐くので例外処理が必須ですが、ChatGPTはdefaultで例外処理を書いてくれませんでした。
次に例外処理を書くように指示した時の関数は以下です。
def divide_numbers(num1, num2):
try:
result = num1 / num2
except ZeroDivisionError:
print("Error: Cannot divide by zero.")
return None
return result
しっかり例外処理が記述されています。
ですがEffective Pythonでは上記のNoneを返すプログラムよりも例外を送出する関数が推奨されています。
def divide_numbers(num1, num2):
try:
return num1 / num2
except ZeroDivisionError:
raise ValueError('Cannot divide by zero')
ラッパー関数の作成(項目26)
プログラムの実行時間を計測するラッパー関数を作成するように指示したら以下のように出力されました。
import time
def measure_time(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"Execution time of '{func.__name__}': {(end_time - start_time):.6f} seconds")
return result
return wrapper
内容は大正解なのですが、Effective Pythonではfunctools.wraps
を用いることが推奨されています。
import time
from functools import wraps
def measure_time(func):
@wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"Execution time of '{func.__name__}': {(end_time - start_time):.6f} seconds")
return result
return wrapper
詳しくはこちらで解説しています。
頑健性と性能
性能確認のプログラム(項目70)
pythonのプログラムがしばしば想定外の振る舞いを引き起こすことがあります。(早いと想定したプログラムが異常に遅いなど)
このようなケースでは、プログラムを最適化する前にプログラム自体の性能を測ることが重要です。
例えば以下のような関数の性能を調査します。
def insert_sort(data):
result = []
for v in data:
insert_value(result, v)
return result
def insert_value(array, v):
for i,existing in enumerate(array):
if existing > v:
array.insert(i,v)
return
array.append(v)
Effective Pythonは以下cProfile
を用いて性能を評価する手法を模範回答としています。(プロファイルする)
from random import randint
from cProfile import Profile
data = [randint(0,10**4) for _ range (10**4)]
test = lambda: insert_sort(data)
profile = Profile()
profile.runcall(test)
stas = Stas(profile)
stats.strip_dirs()
stas.print_stats()
ChatGPTに、「具体的な一つ一つの処理の性能を調査」、または「プログラムを最適化する前にプログラム自体の性能を調査」を指示をします。
その結果は以下です。
import time
import random
def measure_performance(func, data):
start_time = time.time()
result = func(data)
end_time = time.time()
return end_time - start_time, result
data_sizes = [10, 100, 1000, 10000]
for size in data_sizes:
data = list(range(size))
random.shuffle(data)
time_taken, result = measure_performance(insert_sort, data)
print(f"Data size: {size} - Time taken: {time_taken:.5f} seconds")
data_size
でバリエーションを豊富にしてくれましたが、肝心の性能は実行時間を計測する関数で評価する仕様のようです。
ですが、上記プログラムは今回意図しているようなプログラムの性能を詳しくは評価できません。
次に、プロファイルをしてください。というように、プロファイルという専門用語を加えて指示しました。
結果は以下です。
import cProfile
data_sizes = [10, 100, 1000, 10000]
for size in data_sizes:
data = list(range(size))
random.shuffle(data)
# プロファイルの開始
pr = cProfile.Profile()
pr.enable()
insert_sort(data)
pr.disable()
# プロファイリング結果の出力
print(f"Data size: {size}")
pr.print_stats(sort="cumulative")
バッチリです!!
プログラムの性能を測ると指示するよりも、プロファイルといった専門知識を投げかけることが必要でした。
まとめ
ChatGPTは要件に合わせてプログラムを書くことができます。
一方で、ChatGPTの作成したプログラムが最適でないケースも多く見受けられると予想されます。
最適なプログラムを書くためには、まだ我々には、専門的な知識が必要になるでしょう。