简体   繁体   English

在 Python 中使用 *args 和 **kwargs 验证具有默认值的参数

[英]Validating parameters with default value using both *args and **kwargs in Python

I have been looking for the answer to this for sometime but I always end up looking at tutorials covering the basics.一段时间以来,我一直在寻找这个问题的答案,但最终我总是查看涵盖基础知识的教程。 My problem is -我的问题是——

If I have a function:如果我有一个功能:

def foo(a, b, *args, **kwargs):

    if args[0]:
        if args[0] in range(1, 4):
            x=args[0]
        else:
            raise ValueError("Eww that is one ugly x!")
    else:
        x = kwargs.get('x', 3)
    if args[1]:
        if args[1] in ['some','list','of','strings']:
             y = args[1]
        else:
           raise ValueError("Invalid y")
    else:        
        y = kwargs.get('y', "some")

    if x == 1:
       print("Good")
    elif x == 2:
       print("Bad")
    elif x == 3:
       print("Clint")
    else:
       raise ValueError("Eww that is one ugly x!")

    if y == 'some':
       print(y + str(x))
    elif y == 'list':
       print("happy")
    elif y == 'of':
       print("healthy")
    elif y == 'strings':
       print(y + 'me')
    else:
       raise ValueError("Invalid y")

I am looking for a simpler way of treating args[0] and kwargs.get('x') as equivalent - insofar as I would like to perform the same type and value validation checks on which ever is assigned.我正在寻找一种更简单的方法来处理 args[0] 和 kwargs.get('x') 等价物 - 只要我想对分配的任何一个执行相同的类型和值验证检查。 In short how do I map the value of both args[i] and kwargs.get(k) to the same object.简而言之,我如何将 args[i] 和 kwargs.get(k) 的值映射到同一个对象。

Assuming you really want your function to depend on args and kwargs, you could do a try/except statement (telling you if args[0] exist) and use the fact that your ValueError is the same for both cases.假设你真的希望你的函数依赖于 args 和 kwargs,你可以做一个 try/except 语句(告诉你 args[0] 是否存在)并使用你的 ValueError 在两种情况下都相同的事实。

def foo(*args, **kwargs):
    try:
        x = args[0] if args[0] in range(1,4) else None
    except:
        x = kwargs.get('x', 3)

    if x == 1:
       print("Good")
    elif x == 2:
       print("Bad")
    elif x == 3:
       print("Clint")
    else:
       raise ValueError("Eww that is one ugly x!")

I'm curious what your real question is?我很好奇你真正的问题是什么?

If I were simply trying to improve upon your example, I think I would choose the following approach.如果我只是想改进您的示例,我想我会选择以下方法。

from typing import Tuple, Dict, Iterable, Any


def value_from_args_or_kwargs(args: Tuple, index: int, cond: Iterable, error_msg: str,
                              kwargs: Dict, key: str, val: Any):
    if len(args) - 1 >= index and args[index]:
        return args[index] if args[index] in cond else ValueError(error_msg)
    else:
        return kwargs.get(key, val)


def bar(a, b, *args, **kwargs):
    x = value_from_args_or_kwargs(args, 0, range(1, 4), 'Eww that is one ugly x!',
                                  kwargs, 'x', 3)
    y = value_from_args_or_kwargs(args, 1, ['some', 'list', 'of', 'strings'], 'Invalid y',
                                  kwargs, 'y', 'some')
    print('Good') if x == 1 else \
        print('Bad') if x == 2 else \
        print('Client') if x == 3 else ValueError('Eww that is one ugly x!')

    print(f'{y}{x}') if y == 'some' else \
        print('happy') if y == 'list' else \
        print('healthy') if y == 'of' else \
        print(f'{y}me') if y == 'strings' else ValueError('Invalid y')

You should just define your function like this:你应该像这样定义你的函数:

def foo(x):
    if x == 1:
        print("Good")
    elif x == 2:
        print("Bad")
    elif x == 3:
        print("Clint")
    else:
        raise ValueError("Eww that is one ugly x!")

Now you can call this function like:现在你可以像这样调用这个函数:

foo(3)

or as:或作为:

foo(x=3)

There's no need to use *args or **kwargs if you know exactly what arguments you are expecting.如果您确切地知道您期望什么参数,则无需使用*args**kwargs

If you need more arguments, then just name them:如果您需要更多参数,则只需命名它们:

def foo(x, y, z, a, b, c):
    ...

There's no need for *args or **kwargs if you know what arguments you are expecting.如果您知道期望的参数,则不需要*args**kwargs

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM