2009-09-18 70 views
2

我已经做了一个装饰器,我用来确保传递给构造函数的关键字参数是正确/预期的。代码如下: Python装饰器,以确保kwargs正确

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 

使用上面的代码,如果开发商逝者如斯“嗒嗒”的关键ARGS就会抛出一个异常。不幸的是我的实现与继承的一大难题,如果我定义如下:

class PersonTest(Person): 

@keyargs_check(("test")) 
def __init__(self, **kwargs): 
    Person.__init__(self,**kwargs) 

因为我传递kwargs给超类的init方法,我会得到一个例外,因为“测试” 不在传递给超类的装饰器的元组中。有没有办法让超类中使用的装饰器知道额外的关键字?或事件更好,是否有一个标准的方式来实现我想要的?

更新:我更感兴趣的是当我开发人员通过错误的kwarg而不是使用kwargs而不是args时,我抛出异常的方式自动化。我的意思是,我不想编写代码来检查每个班级传递给该方法的参数。

回答

4

您的装饰器没有必要。装饰者所做的唯一不能用标准语法完成的事情是阻止关键字参数吸收位置参数。因此

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) 

这样做的好处是,在kwargsChild不含test。问题是你可以用c = Child('red herring')这样的电话把它弄糟。这是fixed in python 3.0

你的方法存在的问题是你正试图使用​​一个装饰器来完成一个宏的工作,这是一个unpythonic。唯一能让你得到你想要的东西的东西是修改最内层函数的当地人(f在你的代码中,特别是kwargs变量)。你的装饰器应该如何知道包装器的内部,它如何知道它调用了超类?

+0

我理解你的观点,并且我确实考虑过使用* args,但是这给了我一个问题,我不想做以下事情: example = Base(u“”,u“” 26) 并喜欢使用: 例如=基地(年龄= 29) 使用kwargs的理由是,我有很多的争论,我不希望开发者必须通过所有默认值! – mandel 2009-09-18 20:33:07

+1

David编写代码的方式,您不必提供默认参数。你可以构建一个基地(年龄= 29)的基地。 – 2009-09-18 21:17:21

+0

确实,但我想在每个类和我中执行检查,但是使用装饰器会增加代码重用。我不想在每个对象中添加检查。我更喜欢使用装饰器,但即使我使用了一个函数,我也会遇到同样的问题。 – mandel 2009-09-18 22:08:26