Python 如何動態轉發到模組中的同名函式
這是上一篇文章的延伸,檔案結構請參考這篇
CHG: Python 如何動態載入模組中的所有的檔案 (charlottehong.blogspot.com)
主要是想把實作分開到 impl 檔案中,這裡是自動導入的寫法一樣追加在該包的初始話文件中
utils\__init__.py
import importlib
from functools import wraps
# 動態轉發與檔案名稱相同的函式或類別
def forward(target):
# 裝飾器應用於函式時
if callable(target):
@wraps(target)
def wrapper(*args, **kwargs):
# 先執行原始函數(但不使用其返回值)
target(*args, **kwargs)
func_name = target.__name__
try:
# 動態導入目標模組
parent_module = importlib.import_module(f'.{func_name}', package=__package__)
# 獲取同名的函數
target_func = getattr(parent_module, func_name, None)
if target_func is None:
raise AttributeError(f"'{parent_module.__name__}' module has no attribute '{func_name}'")
# 執行轉發函數並返回其結果
return target_func(*args, **kwargs)
except ImportError as e:
raise ImportError(f"Failed to import module for function '{func_name}': {e}")
except AttributeError as e:
raise AttributeError(f"Function '{func_name}' not found in the module '{parent_module.__name__}': {e}")
return wrapper
# 裝飾器應用於類別時
elif isinstance(target, type):
for attr_name, attr_value in target.__dict__.items():
if callable(attr_value) and not attr_name.startswith('__'):
decorated_method = forward(attr_value)
setattr(target, attr_name, decorated_method)
return target
else:
raise TypeError("The @forward decorator can only be applied to functions or classes")
然後就可以在 main 中這樣使用
import utils
@utils.forward
def test_func(name):
pass
@utils.forward
class test_class:
pass
if __name__ == "__main__":
test_func("CHG")
test_class().method()
如此一來就可以自動轉發到同名的函式或類別上了
其中我有保留了原本函式的執行,這是為了把參數前置處理檢查之類的工作可以一同寫在參數定義上,轉發後的函式只需要專注在業務邏輯上
- 執行順序是先原函式然後再轉發的函式
- 原函式的返回值會被丟棄,以轉發的函式的返回值為主
新增在 utils 中有兩個檔案
utils\test_func.py
def test_func(name):
print(f"[name = {name}]")
utils\test_class.py
class test_class:
def method(self):
print("This is a method from test_class in utils.test_class")
沒有留言:
張貼留言