【问题标题】:Python decorator to ensure that kwargs are correct确保 kwargs 正确的 Python 装饰器
【发布时间】:2009-09-18 20:01:57
【问题描述】:

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

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) 

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

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

【问题讨论】:

    标签: python


    【解决方案1】:

    你的装饰器不是必需的。装饰器唯一不能用标准语法完成的事情是防止关键字 args 吸收位置参数。因此

    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') 这样的电话把它搞砸。这是fixed in python 3.0

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

    【讨论】:

    • 我理解你的观点,我确实考虑过使用 *args,但这给了我一个问题,我不想做以下事情:example = Base(u"", u"", 26) 并且更喜欢使用:example = Base(age=29) 使用 kwargs 的原因是我有很多参数,我不希望开发人员必须传递所有默认值!跨度>
    • David 编写代码的方式,您不必提供默认参数。您可以使用 Base(age=29) 构建一个 Base。
    • 确实,但我想在每个类中执行检查,但我认为使用装饰器会增加代码重用。我不想在每个对象中都添加检查。我更喜欢使用装饰器,但即使我使用函数,我也会遇到同样的问题。
    猜你喜欢
    • 2021-08-19
    • 2014-06-08
    • 2018-08-28
    • 1970-01-01
    • 2019-02-06
    • 2011-12-15
    • 1970-01-01
    • 2021-05-19
    相关资源
    最近更新 更多