- 以下のコード例では、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)
- 上記のコードと同様の問題として、
from login import verify_user_statusがデコレータ関数内に配置されています。これは、ファイルの先頭に配置するとloginを実行した際に以下のエラーが発生するためです:
ImportError: cannot import name 'authenticate' from 'decorator'
エラーの原因:login.pyとdecorator.pyの間に相互参照関係があります。
解決策:循環参照のインポート情報を関数内に配置します。どちらか一方の参照情報を関数内に配置すれば十分であり、両方を変更する必要はありません。