What is this?
備忘録的なあれです。
Golangを書いている後、Pythonを書き始めるとエラーをどうあつかったらいいかわからなくなりました。
Golangは基本的に、なにかメソッドを書く際には、必ずといっていい程、エラーも同時に返り値として設定します。そのおかげで、「このエラーはraiseさせよう」とか、「ここはpanicでええやろ」とか、「ここは例外的に処理させねばとか」、逐一考える機会が与えらえて良いなあという印象を受けました。
一方で、Pythonはコード上にて明示的吐き出されません。プログラムを実行した際に、ようやく「ああ、ここはこういうエラーが吐き出されのね、ふーん」みたいなことが多々ありました。
Golangから改めてPythonを触った自分は、エラー出た場合に、try except
で例外処理として、エラーを吐き出すべきなのか、そのままエラーをシステムに吐かせればいいのか、わからなくなりました。
そこで、今回では、どのような場合にエラーをtry except
でログを吐き出すべきなのか、備忘録的に記載していきます。
エラーを例外処理する場合
結論からいうと、
「エラーログに付加要素を付け加えたい場合に例外処理をするべき」
です。
どういうこっちゃかというと、例えばデータベースに接続して検索するケースを挙げます。
下記のような、Mysqlに接続するとします。
import mysql.connector
class DataBaseRepository:
def __init__(self):
self.conn = mysql.connector.connect(
database=MYSQL_DATABASE,
host=MYSQL_HOST,
user=MYSQL_USER,
password=MYSQL_PASS,
charset='utf8mb4',
autocommit=True,
connection_timeout=60,
)
def get_users(self, user_id: int, group_id: int) -> [str]:
"""
get username
:return list of username
"""
cursor = self.conn.cursor
sql =
f"""
SELECT name
FROM users
WHERE user_id = {user_id}
AND group_id = {group_id}
"""
cursor.execute(sql)
return cursor.fetchall()
def close(self):
self.conn.close()
def __del__(self):
self.close()
DataBaseに接続して、get_users
で user_id
と group_id
が一致するuserの name
を取得します。(そのほかのメソッドは、説明は省きます)
このコードを用いた下記のような2種類実行のコードがあるとします。
- 例外処理を書く場合
from logging import getLogger
if __name__ == '__main__':
logger = getLogger(__name__)
repo = DataBaseRepository()
user_id = 100
group_id = 1
try:
user_names = repo.get_users(group_id, gender_id)
except:
"""
ここにどうような処理を書くべき?
"""
if len(user_names) == 0 {
logger.warn('user_name size is zero!')
}
- 例外処理を書かない場合
from logging import getLogger
if __name__ == '__main__':
repo = DataBaseRepository()
user_id = 100
group_id = 1
user_names = repo.get_users(group_id, gender_id)
if len(user_names) == 0 {
logger.warn('user_name size is zero!')
}
どっちがいいと思いますか?
どっちでも、エラーがでるときは十分ありうるコードなのです。DataBaseのカラムが存在しないかもしれないし、Connectionが確立されてないかもしれないし、そもそもレコードがないこともありえますね。
その場合、より多くの情報があった方が不足の事態に対処しやすいです。
この情報が 付加要素
となるわけです。
例えば、今回の場合だと、group_id
と gender_id
があった方が、断然エラー対応しやすいです。
なので、エラーがでる部分を例外処理でくくって、付加要素を加えます。
- 例外処理を書く場合
from logging import getLogger
if __name__ == '__main__':
logger = getLogger(__name__)
repo = DataBaseRepository()
user_id = 100
group_id = 1
try:
user_names = repo.get_users(group_id, gender_id)
except Exception as e:
"""
ここにどうような処理を書くべき?
"""
logger.error(f'Failed to get user_name of group_id:{group_id} and gender_id:{gender_id}')
raise(e)
if len(user_names) == 0 {
logger.warn('user_name size is zero!')
}
これで、エラー対応が楽になるはず。。。
まとめ
要約すると
「エラー対応がしやすいように、付加要素的なエラーログを意識しましょう」
以上。
何か、ご意見やご指摘あれば、何卒コメント欄にご記入いただけますと幸いです。