Python装饰器找到密钥存在,并将其作为参数传递

时间:2013-10-23 22:21:39

标签: python dictionary

我想知道我是否可以使用装饰器来查看函数的输入是否为:

  1. 字典,如果不是字典,则运行方法
  2. 如果是字典,则从中提取指定的密钥,并将其传递给方法
  3. 示例:

    @get_values(['username', 'password'])
        def log_me_in(username, password)
           # login logic
           if username == password:
               return True
           return False
    

    称呼它的方式:

    log_me_in(username = 10, password = 10)
    >>>> True
    log_me_in(10, 10)
    >>>> True
    log_me_in({'username': 10, 'password': 10})
    >>>> True
    log_me_in({'username': 10, 'password': 10, 'something': 10})
    >>>> True
    log_me_in({'username': 10, 'something': 10})
    >>>> EXCEPTION
    log_me_in({})
    >>>> EXCEPTION
    log_me_in([])
    >>>> EXCEPTION
    

2 个答案:

答案 0 :(得分:1)

如果要将值作为位置参数传递(根据传递给装饰器的参数列表中的位置):

def getvalues(params):
    getter = itemgetter(*params)
    def deco(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            if len(args) == 1 and not kwargs and isinstance(args[0], Mapping):
                return func(*getter(args[0]))
            else:
                return func(*args, **kwargs)
        return wrapper
    return deco

如果您想将它们作为关键字参数传递:

def getvalues(params):
    def deco(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            if len(args) == 1 and not kwargs and isinstance(args[0], Mapping):
                return func(**{key: value for key, value in args[0].items() 
                               if key in params})
            else:
                return func(*args, **kwargs)
        return wrapper
    return deco

我必须制定自己的规则来填补规范中的所有空白,但我认为它们有点合理。

另外,正如我在评论中提到的,如果getvalues将其参数名称作为单独的参数而不是列表,我认为会更友好。要解决此问题,只需将第一行更改为def getvalues(*params):

答案 1 :(得分:0)

有可能,是的。但这有必要吗?您可以通过使用**传递关键字参数来获得类似的结果:

>>> log_me_in(**{'username': 10, 'password': 10})
True

唯一的区别是不允许传递something。 Python在无法识别的关键字参数上出错。参见:

>>> log_me_in(username=10, password=10)
True
>>> log_me_in(10, 10)
True
>>> log_me_in(**{'username': 10, 'password': 10})
True
>>> log_me_in(**{'username': 10, 'password': 10, 'something': 10})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: log_me_in() got an unexpected keyword argument 'something'
>>> log_me_in(**{'username': 10, 'something': 10})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: log_me_in() got an unexpected keyword argument 'something'
>>> log_me_in(**{})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: log_me_in() missing 2 required positional arguments: 'username' and 'password'
>>> log_me_in(*[])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: log_me_in() missing 2 required positional arguments: 'username' and 'password'