python装饰器函数
-
装饰器函数是 Python 中一种特殊的函数,它可以修改或增强其他函数或类的功能,而不需要修改它们的源代码
一个简单的例子,在
register.py
中写下一个装饰器函数:def test(original_function): def wrapper(*args, **kwargs): print("This is a wrapper function") result = original_function(*args, **kwargs) print("This is after the wrapper function") return result return wrapper
新建一个
usage.py
,导入这个方法后增强某一函数功能,如下:from register import test @test def register(username, password): print(f"Registering user {username} with password {password}") if __name__ == "__main__": register("testuser", "testpassword")
没错,控制台打印出来的结果如下:
This is a wrapper function Registering user testuser with password testpassword This is after the wrapper function
结论:虽然函数的函数体只定义了
print(f"Registering user {username} with password {password}")
,实际上却不仅如此。由此可以总结,多余的打印信息是对当前文件透明的,可以用作日志信息或其他,接着往下
-
打印日志
可以添加日志信息,打印日志过程对函数透明,如下:
def logged_funct(function): def wrapper(*args, **kwargs): print(f"Logging {function.__name__} with args {args} and kwargs {kwargs}") result = function(*args, **kwargs) print(f"Finished logging {function.__name__}") return result return wrapper
装饰一个简单函数:
@logged_funct def add(a, b): return a + b
控制台输出:
Logging add with args (1, 2) and kwargs {} Finished logging add
*args
用于将函数调用时传入的多个位置参数(非关键字参数)打包成一个元组(tuple)调用
func(1, 2, 3, 4)
时,args
会是一个元组(1, 2, 3, 4)
。**kwargs
用于将函数调用时传入的多个关键字参数打包成一个字典(dict)调用
func(a=1, b=2, c=3)
时,kwargs
会是一个字典{'a': 1, 'b': 2, 'c': 3}
。当然,这只是简单的示例,可以根据需求扩展。
-
计算函数执行时间、参数检测等
-
函数执行时间
def time_compute(function): def wrapper(*args, **kwargs): start_time = time.time() function(*args, **kwargs) end_time = time.time() print(f"Time taken: {end_time - start_time} seconds") return end_time - start_time return wrapper
-
-
机器学习中注册数据集:
def register_dataset(fn): data_name = fn.__name__ if data_name not in _dataset_dict: _dataset_dict[fn.__name__] = fn else: raise ValueError(f"{data_name} already exists in dataset_dict") return fn @register_dataset class CustomDataset(datasets.VisionDataset): # 类的实现代码
-
@property装饰器
当我们不使用装饰器时,访问和修改受保护的成员时:
class ExampleClass: def __init__(self): self._value = 0 #单下划线_:用于表示受保护的成员,是一种约定,提示程序员不要在类外部直接访问,但Python不会强制限制访问。 双下划线__:用于表示私有成员,Python会进行名称改写,以避免在子类中被意外覆盖,从而实现更严格的封装。 def get_value(self): return self._value def set_value(self, new_value): if new_value >= 0: self._value = new_value else: raise ValueError("Value must be non-negative") obj = ExampleClass() print(obj.get_value()) # 获取属性值 obj.set_value(5) # 设置属性值 print(obj.get_value()) # obj.set_value(-1) # 会引发 ValueError
十分繁琐,使用修饰器后:
class ExampleClass: def __init__(self): self._value = 0 @property def value(self): return self._value @value.setter def value(self, new_value): if new_value >= 0: self._value = new_value else: raise ValueError("Value must be non-negative") # 使用示例 obj = ExampleClass() print(obj.value) # 作为属性访问 obj.value = 5 # 作为属性设置 print(obj.value) # obj.value = -1 # 会引发 ValueError
逻辑清晰,像是访问属性一样,实际上是调用函数。
可以在 @property 装饰的方法中添加更多的逻辑,如计算属性值、缓存结果等,而不影响外部代码的调用方式。
当然还可以删除属性:
@content.deleter def content(self): print("Deleting content") self._content = None del file.content