Python開発における一般的な落とし穴と解決策

  1. 以下のコード例では、login.pyを実行すると関数が二回実行される問題が発生します。
login.py

from decorator import authenticate
def verify_user_status(status):
    if status == "active":
        return True
    elif status == "inactive":
        return False
@authenticate
def publish_comment(content):
    return "コメント投稿成功: " + content
result = publish_comment('active')
print(result)
decorator.py
def authenticate(func):
    def wrapper(*args, **kwargs):
        user_status = args[0]
        from login import verify_user_status # ここでloginモジュール全体をインポートしているため、デコレータが二回実行される
        if verify_user_status(user_status):
            return_value = func(*args, **kwargs)
        else:
            raise Exception('認証失敗')
        return return_value
    return wrapper

関数が二回実行されないようにするには、if __name__ == '__main__': を追加します。これにより、以下のコードは現在のファイルが直接実行された場合のみ実行されます。

具体的な原因はlogin.pyにあります。print(__name__) を実行すると、__main__ と出力されます。つまり、loginモジュールの__name____main__の場合にのみ、以下のコードが実行されます。これにより、モジュールが他のファイルからインポートされた際にコードが実行されるのを防ぐことができます。モジュールのインポートを正しく理解することが重要です。

修正後のloginコード:

from decorator import authenticate
def verify_user_status(status):
    if status == "active":
        return True
    elif status == "inactive":
        return False
@authenticate
def publish_comment(content):
    return "コメント投稿成功: " + content
if __name__ == '__main__':
    result = publish_comment('active')
    print(result)
  1. 上記のコードと同様の問題として、from login import verify_user_status がデコレータ関数内に配置されています。これは、ファイルの先頭に配置するとloginを実行した際に以下のエラーが発生するためです:

ImportError: cannot import name 'authenticate' from 'decorator'

エラーの原因:login.pyとdecorator.pyの間に相互参照関係があります。

解決策:循環参照のインポート情報を関数内に配置します。どちらか一方の参照情報を関数内に配置すれば十分であり、両方を変更する必要はありません。

タグ: Python デコレーター モジュールインポート 循環インポート ベストプラクティス

7月27日 17:37 投稿