方法装饰器的Pythonic应用?
我试图理解如何编写一个decorator来检查每个方法的main_val属性,特别是当main_val属性的位置可能会改变,甚至有一个默认值时。另外,是否有一种更适合应用这种条件的方法 我在下面写了一个例子来直观地描述这个问题,希望有更多经验的人能够解释 对于下面的每个方法,main_val应该是我的decorator应该检查的唯一属性。我不确定如何强制装饰器始终检查main_val,除非它作为key=value属性传递或引用*args中的硬编码位置方法装饰器的Pythonic应用?,python,python-3.x,decorator,Python,Python 3.x,Decorator,我试图理解如何编写一个decorator来检查每个方法的main_val属性,特别是当main_val属性的位置可能会改变,甚至有一个默认值时。另外,是否有一种更适合应用这种条件的方法 我在下面写了一个例子来直观地描述这个问题,希望有更多经验的人能够解释 对于下面的每个方法,main_val应该是我的decorator应该检查的唯一属性。我不确定如何强制装饰器始终检查main_val,除非它作为key=value属性传递或引用*args中的硬编码位置 class TestCase: de
class TestCase:
def __init__(self):
self.allowable_list = [1,2,3,4,5]
def decorator_check(func):
# I want to apply condition to "main_val" attribute of any method this decorator is applied to
def wrapper(self, val, *args, **kwargs):
if val not in self.allowable_list:
raise AttributeError("value {} not in allowable list {}".format(val, self.allowable_list))
return func(self, val, *args, **kwargs)
return wrapper
@decorator_check
def calc(self, main_val, val_num_two, val_num_three):
print("(calc) - main_val: {} val_num_two: {} val_num_three: {}".format(main_val, val_num_two, val_num_three))
return main_val * val_num_two * val_num_three
@decorator_check
def calc_two(self, another_val, main_val, val_num_two):
print("(calc_two) - another_val: {} main_val: {} val_num_two: {}".format(another_val, main_val, val_num_two))
return another_val * main_val * val_num_two
@decorator_check
def calc_three(self, another_val, val_num_two, main_val=3):
print("(calc_two) - another_val: {} main_val: {} val_num_two: {}".format(another_val, main_val, val_num_two))
return another_val * val_num_two * main_val
test_obj = TestCase()
按预期返回错误
test_obj.calc_two(2, 5, 3)
返回(计算二)-另一个值:2主值:5值数:3
test_obj.calc_three(2,5,100)
返回值(计算值2)-另一个值:2值数:5主值:100
解决此问题的方法有哪些?用于确定签名、绑定参数、应用默认值以及计算main\u val
的最终值:
import functools
import inspect
def main_val_decorator(f):
f_sig = inspect.signature(f)
@functools.wraps(f)
def wrapper(*args, **kwargs):
bound = f_sig.bind(*args, **kwargs)
bound.apply_defaults()
main_val = bound.arguments['main_val']
do_whatever_with(main_val)
return f(*args, **kwargs)
return wrapper
这做的工作比您需要的要多,因为它也为所有其他参数确定绑定,但比手动执行内省方便得多。用于确定签名、绑定参数、应用默认值以及计算main\u val
的最终值:
import functools
import inspect
def main_val_decorator(f):
f_sig = inspect.signature(f)
@functools.wraps(f)
def wrapper(*args, **kwargs):
bound = f_sig.bind(*args, **kwargs)
bound.apply_defaults()
main_val = bound.arguments['main_val']
do_whatever_with(main_val)
return f(*args, **kwargs)
return wrapper
这做的工作比您需要的要多,因为它也确定了所有其他参数的绑定,但它比手动执行内省方便得多。这与您的主要问题无关,但在您使用它的情况下,
AttributeError肯定不是正确的例外。该错误表明属性查找obj.attr
失败,因为attr
不存在。我认为您可能应该使用ValueError
,因为当您将错误值的参数传递给函数或方法时,通常会出现这种情况。由于您的装饰程序正在根据允许的值列表检查您传递的值,这似乎是最合适的。谢谢@Blckknght!我只是查了一下定义,没有意识到是这样的。这与你的主要问题无关,但在你使用它的情况下,AttributeError
肯定不是正确的例外。该错误表明属性查找obj.attr
失败,因为attr
不存在。我认为您可能应该使用ValueError
,因为当您将错误值的参数传递给函数或方法时,通常会出现这种情况。由于您的装饰程序正在根据允许的值列表检查您传递的值,这似乎是最合适的。谢谢@Blckknght!我只是查了一下定义,并没有意识到是这样的。这有点过分了——但还是有用的。希望有一个更简单的解决方案,如果你想处理一个可能在方法签名中任何地方的值,我想这大概是最简单的。对于较窄的情况(例如,如果参数仅为关键字),您可以提出自己的自定义解决方案,该解决方案可能更简单,但这可能是唯一好的通用解决方案。感谢各位-有一点我不太明白,functools.wrapps在这种情况下有什么意义?似乎没有必要这有点过分了,但还是有用的。希望有一个更简单的解决方案,如果你想处理一个可能在方法签名中任何地方的值,我想这大概是最简单的。对于较窄的情况(例如,如果参数仅为关键字),您可以提出自己的自定义解决方案,该解决方案可能更简单,但这可能是唯一好的通用解决方案。感谢各位-有一点我不太明白,functools.wrapps在这种情况下有什么意义?似乎没有必要