确保kwargs正确的Python装饰器
我写了一个装饰器,用来确保传给构造函数的关键字参数是正确的/预期的。下面是代码:
from functools import wraps
def keyargs_check(keywords):
"""
This decorator ensures that the keys passed in kwargs are the onces that
are specified in the passed tuple. When applied this decorate will
check the keywords and will throw an exception if the developer used
one that is not recognized.
@type keywords: tuple
@param keywords: A tuple with all the keywords recognized by the function.
"""
def wrap(f):
@wraps(f)
def newFunction(*args, **kw):
# we are going to add an extra check in kw
for current_key in kw.keys():
if not current_key in keywords:
raise ValueError(
"The key {0} is a not recognized parameters by {1}.".format(
current_key, f.__name__))
return f(*args, **kw)
return newFunction
return wrap
这个装饰器的一个使用例子是这样的:
class Person(object):
@keyargs_check(("name", "surname", "age"))
def __init__(self, **kwargs):
# perform init according to args
使用上面的代码,如果开发者传了一个像“blah”这样的关键字参数,就会抛出一个异常。不过,我的实现有一个大问题,就是在继承的时候。如果我定义如下:
class PersonTest(Person):
@keyargs_check(("test"))
def __init__(self, **kwargs):
Person.__init__(self,**kwargs)
因为我把关键字参数传给了父类的初始化方法,所以会出现异常,因为“test”不在传给父类装饰器的元组中。有没有办法让父类的装饰器知道这些额外的关键字参数?或者更好的是,有没有标准的方法可以实现我想要的功能?
更新:我更关心的是如何自动抛出异常,当开发者传入错误的关键字参数,而不是我使用关键字参数而不是位置参数。我的意思是,我不想在每个类中都写检查传入方法的参数的代码。
1 个回答
4
你的装饰器其实是没必要的。装饰器唯一能做到的,就是防止关键字参数(keyword args)把位置参数(positional arguments)给吸收掉。所以
class Base(object):
def __init__(name=None,surname=None,age=None):
#some code
class Child(Base):
def __init__(test=None,**kwargs):
Base.__init__(self,**kwargs)
这样做的好处是,Child
里的kwargs
不会包含test
。不过问题是,如果你像这样调用:c = Child('red herring')
,就可能搞乱了。这在 Python 3.0中已经修复了。
你这个方法的问题在于,你试图用装饰器来做宏(macro)的工作,这样做不符合Python的风格。想要实现你想要的效果,唯一的方法就是修改最里面函数的局部变量(在你的代码中是f
,具体来说是kwargs
变量)。你的装饰器怎么知道包装函数的内部情况呢?它又怎么知道自己调用的是父类呢?