class 方法上的条件 属性 装饰器
Conditional property decorator on class method
我有一个 python 数据类,我想在其中根据某些全局变量有条件地分配某些装饰器。
在脚本顶部检查条件,但对于下面的示例,我只是提供了检查结果。如果检查是 True
,我想为这些方法提供 @functools.cached_property
装饰器。如果是 False
,我只想让他们收到标准的 @property
装饰器。
我一直 运行 关注的问题是我无法完全弄清楚如何(或者如果可能的话)使它作为一个简单的装饰器工作。在调用或操作 test.x_times_y
时,我通常会遇到有关方法对象的错误,而且我不确定是否可以按照下面示例中调用 test.x_times_y
实际产生结果的方式编写函数我想要的。
import functools
import dataclasses
_value_checked = False
def myDecorator(func):
def decorator(self):
if not _value_checked:
return property(func)(self)
else:
return functools.cached_property(func)(self)
return decorator
@dataclasses.dataclass
class MyClass():
x: int
y: int
z: int = 0
@myDecorator
def x_times_y(self):
return self.x*self.y
test = MyClass(5,6,7)
我还想避免使用 getter 和 setter 方法,所以我希望这是可能的。我在这里查看了很多答案(例如 this one),但未能找到实际有效的答案,因为大多数不适用于装饰方法。我为此使用 Python 3.8。
您编写的方式myDecorator
它只能应用于采用单个参数的函数:
def myDecorator(func):
def decorator(self):
if not _value_checked:
return property(func)(self)
else:
return functools.cached_property(func)(self)
return decorator
最简单的方法是只 return 函数而不是在包装器中调用它:
def myDecorator(func):
if not _value_checked:
return property(func)
else
return functools.cached_property(func)
如果您确实需要构建包装器,通常正确的方法是让包装器函数采用任意 *args, **kwargs
个参数,以便您可以使用它们调用包装函数:
def myDecorator(func):
def wrapper(*args, **kwargs):
if not _value_checked:
return property(func)(*args, **kwargs)
else:
return functools.cached_property(func)(*args, **kwargs)
return wrapper
请注意 myDecorator
returns 的函数 本身 不是装饰器,它是替换装饰函数的包装器——这就是为什么我在上面的实现中重命名了它。
另请注意,这些实现之间存在实际差异,即第二个版本(带有包装器)在调用函数时计算 _value_checked
,而第一个版本在定义函数时 对其求值 。如果该值是一个常量,那没关系,但如果您希望能够在运行时切换它并动态改变行为,您需要第二个版本。
您想要的行为可以通过简单的条件赋值实现:
my_decorator = functools.cached_property if _value_checked else property
或
if _value_checked:
my_decorator = functools.cached_property
else:
my_decorator = property
如果你需要在每次使用装饰器时做更复杂的逻辑,你可以使用一个函数,returns你想要的装饰器:
def my_decorator():
if not _value_checked:
return property
else
return functools.cached_property
不需要复杂的参数转发。只需委托给您已有的装饰器即可。
我有一个 python 数据类,我想在其中根据某些全局变量有条件地分配某些装饰器。
在脚本顶部检查条件,但对于下面的示例,我只是提供了检查结果。如果检查是 True
,我想为这些方法提供 @functools.cached_property
装饰器。如果是 False
,我只想让他们收到标准的 @property
装饰器。
我一直 运行 关注的问题是我无法完全弄清楚如何(或者如果可能的话)使它作为一个简单的装饰器工作。在调用或操作 test.x_times_y
时,我通常会遇到有关方法对象的错误,而且我不确定是否可以按照下面示例中调用 test.x_times_y
实际产生结果的方式编写函数我想要的。
import functools
import dataclasses
_value_checked = False
def myDecorator(func):
def decorator(self):
if not _value_checked:
return property(func)(self)
else:
return functools.cached_property(func)(self)
return decorator
@dataclasses.dataclass
class MyClass():
x: int
y: int
z: int = 0
@myDecorator
def x_times_y(self):
return self.x*self.y
test = MyClass(5,6,7)
我还想避免使用 getter 和 setter 方法,所以我希望这是可能的。我在这里查看了很多答案(例如 this one),但未能找到实际有效的答案,因为大多数不适用于装饰方法。我为此使用 Python 3.8。
您编写的方式myDecorator
它只能应用于采用单个参数的函数:
def myDecorator(func):
def decorator(self):
if not _value_checked:
return property(func)(self)
else:
return functools.cached_property(func)(self)
return decorator
最简单的方法是只 return 函数而不是在包装器中调用它:
def myDecorator(func):
if not _value_checked:
return property(func)
else
return functools.cached_property(func)
如果您确实需要构建包装器,通常正确的方法是让包装器函数采用任意 *args, **kwargs
个参数,以便您可以使用它们调用包装函数:
def myDecorator(func):
def wrapper(*args, **kwargs):
if not _value_checked:
return property(func)(*args, **kwargs)
else:
return functools.cached_property(func)(*args, **kwargs)
return wrapper
请注意 myDecorator
returns 的函数 本身 不是装饰器,它是替换装饰函数的包装器——这就是为什么我在上面的实现中重命名了它。
另请注意,这些实现之间存在实际差异,即第二个版本(带有包装器)在调用函数时计算 _value_checked
,而第一个版本在定义函数时 对其求值 。如果该值是一个常量,那没关系,但如果您希望能够在运行时切换它并动态改变行为,您需要第二个版本。
您想要的行为可以通过简单的条件赋值实现:
my_decorator = functools.cached_property if _value_checked else property
或
if _value_checked:
my_decorator = functools.cached_property
else:
my_decorator = property
如果你需要在每次使用装饰器时做更复杂的逻辑,你可以使用一个函数,returns你想要的装饰器:
def my_decorator():
if not _value_checked:
return property
else
return functools.cached_property
不需要复杂的参数转发。只需委托给您已有的装饰器即可。