Pythonで変数の存在確認
当時私は新入社員として、あるWebサービスの開発プロジェクトに携わっていました。 担当したのは、ユーザーの購入履歴に基づいておすすめ商品を表示する機能です。意気揚々と開発を進め、テストも問題なく完了。自信満々で本番環境にリリースしました。
しかし、リリースから数日後、想定外の事態が発生しました。一部のユーザーに、全く関係のない商品が表示されてしまうという不具合が報告されたのです。調査の結果、原因は私のコードにあることが判明しました。
問題点は、変数の名前のスペルミスでした。
purchase_history
という変数名を使用するべきところを、誤ってpurchase_hisotry
と記述していたのです。たった1文字の違いなのに、プログラムは全く異なる意味として解釈し、誤った商品を表示していたのです。
この不具合の影響は深刻でした。ユーザーは混乱し、信頼を失墜。さらに、誤った商品購入によるキャンセルや返品が相次ぎ、会社は100万円以上の損失を被りました。
この失敗は、変数の未定義チェックを怠っていたことが原因です。 コードレビューの際に、スペルミスを見逃してしまっていたのです。
Pythonの未定義変数を判定
Pythonで未定義変数を使用すると、原因不明なエラーが発生したり、プログラムが不安定になったりする可能性があります。また、プログラムが実行されると不必要なメモリを使用する可能性があります。また、未定義変数を使用すると、コードを理解しにくくなる可能性もあります。
そのため、変数が未定義かどうかを判定する必要が出てくるんですね。try~exceptでNameErrorをキャッチすることで未定義判定ができます。
以下は、変数nameが未定義かどうか判定するサンプルコードです。
try: print(name) except NameError: print('変数nameが未定義です。')
変数nameで例外NameErrorが発生した場合に、未定義であるというメッセージを表示します。NameErrorは、存在しない変数や定数などにアクセスしようとしたときに発生します。
変数nameが未定義です。
上記の例では、変数ごとにtry~exceptを指定しないと未定義変数の出現箇所がわかりません。
Pythonでは、変数名をタイプミスして値を代入しても特に警告も出ないので、バグに気づきにくいという可能性があるんですね。
Pythonのコード内で未定義変数に値を代入している箇所をチェックするには、pyflakesというツールを使うと良いでしょう。 pyflakesは、Pythonコード内で未定義変数を検出するツールです。pyflakesは無料で利用できるオープンソースのツールなので、お手軽に使うことができます。
Pythonの未定義関数
関数が未定義かどうかは、関数呼び出し時にNameError例外が発生するかどうかで判定できます。
def is_defined(function_name): try: eval(function_name) return True except NameError: return False if __name__ == '__main__': print(is_defined('print')) print(is_defined('foo'))
eval関数は、文字列を実行可能なPythonコードとして評価する関数です。関数を指定した場合、その関数を実行し、その結果を返します。
実行するとこうなります。print関数は定義済み、foo関数は未定義という判定になりました。
True False
Pythonの未定義配列
Pythonの配列は、空だと未定義扱いになります。未定義かどうかを判定するサンプルコードは以下の通り。notを使って未定義配列の判定が可能です。
arr = [] if not arr: print('未定義')
実行するとこうなります。arrは空の配列ですが、notを使って判定すると未定義となりました。
未定義
関連)Pythonの配列
Pythonの未定義辞書
inを使って辞書の未定義の判定が可能です。
以下は、辞書にOrangeというキーが定義されているかどうかを判定するサンプルコードです。
my_dictionary = { 'Apple': '小さな青い果物', 'Banana': '黄色い果物' } key = 'Orange' if key in my_dictionary: print(f'{key} の値は {my_dictionary[key]} です。') else: print(f'{key} は未定義です。')
実行するとこうなります。
Orange は未定義です。
Pythonの未定義のまとめ
- Pythonで未定義の変数や関数はNameError例外が発生するかどうかで判定する
- 配列の未定義判定はnotを使って判定する
- 辞書に指定のキーが定義済みかどうかは、inを使って判定する