代码之家  ›  专栏  ›  技术社区  ›  l7ll7

CPython如何评估“*args”?[副本]

  •  0
  • l7ll7  · 技术社区  · 6 年前

    在下面的方法定义中 * ** 为…做 param2

    def foo(param1, *param2):
    def bar(param1, **param2):
    
    0 回复  |  直到 6 年前
        1
  •  2
  •   Raj    5 年前

    这个 *args **kwargs more on defining functions 在Python文档中。

    这个 会给你所有的功能参数 as a tuple

    def foo(*args):
        for a in args:
            print(a)        
    
    foo(1)
    # 1
    
    foo(1,2,3)
    # 1
    # 2
    # 3
    

    这个 **夸尔格斯 会给你所有的 除了那些对应于作为字典的形式参数。

    def bar(**kwargs):
        for a in kwargs:
            print(a, kwargs[a])  
    
    bar(name='one', age=27)
    # age 27
    # name one
    

    def foo(kind, *args, **kwargs):
       pass
    

    也可以反过来使用:

    def foo(a, b, c):
        print(a, b, c)
    
    obj = {'b':10, 'c':'lee'}
    
    foo(100,**obj)
    # 100 10 lee
    

    *l 习语是 打开参数列表 调用函数时。

    def foo(bar, lee):
        print(bar, lee)
    
    l = [1,2]
    
    foo(*l)
    # 1 2
    

    在Python 3中可以使用 在作业的左边( Extended Iterable Unpacking ),尽管它在此上下文中提供了列表而不是元组:

    first, *rest = [1,2,3,4]
    first, *l, last = [1,2,3,4]
    

    Python 3还添加了新的语义(参见 PEP 3102 ):

    def func(arg1, arg2, arg3, *, kwarg1, kwarg2):
        pass
    

    这样的函数只接受3个位置参数,并且 * 只能作为关键字参数传递。

        2
  •  0
  •   RBF06    6 年前

    值得注意的是,您可以使用 * ** 同时调用函数时。这是一个快捷方式,允许您使用列表/元组或字典直接向函数传递多个参数。例如,如果您具有以下功能:

    def foo(x,y,z):
        print("x=" + str(x))
        print("y=" + str(y))
        print("z=" + str(z))
    

    你可以这样做:

    >>> mylist = [1,2,3]
    >>> foo(*mylist)
    x=1
    y=2
    z=3
    
    >>> mydict = {'x':1,'y':2,'z':3}
    >>> foo(**mydict)
    x=1
    y=2
    z=3
    
    >>> mytuple = (1, 2, 3)
    >>> foo(*mytuple)
    x=1
    y=2
    z=3
    

    注:钥匙在 mydict foo . 否则它会抛出 TypeError :

    >>> mydict = {'x':1,'y':2,'z':3,'badnews':9}
    >>> foo(**mydict)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: foo() got an unexpected keyword argument 'badnews'
    
        3
  •  0
  •   dreftymac    5 年前

    单个*表示可以有任意数量的额外位置参数。 foo() 可以调用如下 foo(1,2,3,4,5)

    double**表示可以有任意数量的额外命名参数。 bar() 可以调用如下 bar(1, a=2, b=3)

    使用以下代码:

    def foo(param1, *param2):
        print(param1)
        print(param2)
    
    def bar(param1, **param2):
        print(param1)
        print(param2)
    
    foo(1,2,3,4,5)
    bar(1,a=2,b=3)
    

    输出是

    1
    (2, 3, 4, 5)
    1
    {'a': 2, 'b': 3}
    
        4
  •  0
  •   Meysam Sadeghi    5 年前

    做什么 ** (双星)和 *

    他们允许 要定义为接受的函数 要通过的用户 任意数量的参数,位置( * )和关键字( ).

    定义函数

    *args args .

    **kwargs 允许任意数量的可选关键字参数(参数),这些参数将在名为 kwargs

    您可以(并且应该)选择任何适当的名称,但是如果目的是使参数具有非特定的语义, 关键字参数

    扩展,传递任意数量的参数

    你也可以使用 *参数 **夸尔格斯

    接收参数的函数不必知道它们正在被扩展。

    例如,Python 2的xrange没有显式地期望 *参数

    >>> x = xrange(3) # create our *args - an iterable of 3 integers
    >>> xrange(*x)    # expand here
    xrange(0, 2, 2)
    

    str.format :

    >>> foo = 'FOO'
    >>> bar = 'BAR'
    >>> 'this is foo, {foo} and bar, {bar}'.format(**locals())
    'this is foo, FOO and bar, BAR'
    

    Python 3中的新特性:仅用关键字参数定义函数

    你可以 keyword only arguments 之后 *参数 -例如,在这里, kwarg2 必须作为关键字参数提供-而不是位置参数:

    def foo(arg, kwarg=None, *args, kwarg2=None, **kwargs): 
        return arg, kwarg, args, kwarg2, kwargs
    

    用法:

    >>> foo(1,2,3,4,5,kwarg2='kwarg2', bar='bar', baz='baz')
    (1, 2, (3, 4, 5), 'kwarg2', {'bar': 'bar', 'baz': 'baz'})
    

    也, 可以自己使用来指示后面只跟关键字参数,而不允许无限的位置参数。

    def foo(arg, kwarg=None, *, kwarg2=None, **kwargs): 
        return arg, kwarg, kwarg2, kwargs
    

    在这里, 同样必须是显式命名的关键字参数:

    >>> foo(1,2,kwarg2='kwarg2', foo='foo', bar='bar')
    (1, 2, 'kwarg2', {'foo': 'foo', 'bar': 'bar'})
    

    我们不能再接受无限的位置参数,因为我们没有 *args* :

    >>> foo(1,2,3,4,5, kwarg2='kwarg2', foo='foo', bar='bar')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: foo() takes from 1 to 2 positional arguments 
        but 5 positional arguments (and 1 keyword-only argument) were given
    

    kwarg 按名称而不是按位置给出:

    def bar(*, kwarg=None): 
        return kwarg
    

    在这个例子中,我们看到如果我们试图通过 在位置上,我们得到一个错误:

    >>> bar('kwarg')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: bar() takes 0 positional arguments but 1 was given
    

    我们必须明确通过 夸尔格 参数作为关键字参数。

    >>> bar(kwarg='kwarg')
    'kwarg'
    

    Python2兼容演示

    (通常称为“星号args”)和 **夸尔格斯 * ** 符号。这些特定的变量名不是必需的(例如,您可以使用 *foos **bars

    我们通常在不知道函数将接收什么或传递多少参数时使用这些函数,有时甚至在分别命名每个变量时也会变得非常混乱和多余(但在这种情况下,通常显式优于隐式)。

    例1

    b 参数将由以下位置之前的第二个位置参数使用:

    def foo(a, b=10, *args, **kwargs):
        '''
        this function takes required argument a, not required keyword argument b
        and any number of unknown positional arguments and keyword arguments after
        '''
        print('a is a required argument, and its value is {0}'.format(a))
        print('b not required, its default value is 10, actual value: {0}'.format(b))
        # we can inspect the unknown arguments we were passed:
        #  - args:
        print('args is of type {0} and length {1}'.format(type(args), len(args)))
        for arg in args:
            print('unknown arg: {0}'.format(arg))
        #  - kwargs:
        print('kwargs is of type {0} and length {1}'.format(type(kwargs),
                                                            len(kwargs)))
        for kw, arg in kwargs.items():
            print('unknown kwarg - kw: {0}, arg: {1}'.format(kw, arg))
        # But we don't have to know anything about them 
        # to pass them to other functions.
        print('Args or kwargs can be passed without knowing what they are.')
        # max can take two or more positional args: max(a, b, c...)
        print('e.g. max(a, b, *args) \n{0}'.format(
          max(a, b, *args))) 
        kweg = 'dict({0})'.format( # named args same as unknown kwargs
          ', '.join('{k}={v}'.format(k=k, v=v) 
                                 for k, v in sorted(kwargs.items())))
        print('e.g. dict(**kwargs) (same as {kweg}) returns: \n{0}'.format(
          dict(**kwargs), kweg=kweg))
    

    help(foo) ,它告诉我们

    foo(a, b=10, *args, **kwargs)
    

    让我们用 foo(1, 2, 3, 4, e=5, f=6, g=7)

    打印内容:

    a is a required argument, and its value is 1
    b not required, its default value is 10, actual value: 2
    args is of type <type 'tuple'> and length 2
    unknown arg: 3
    unknown arg: 4
    kwargs is of type <type 'dict'> and length 3
    unknown kwarg - kw: e, arg: 5
    unknown kwarg - kw: g, arg: 7
    unknown kwarg - kw: f, arg: 6
    Args or kwargs can be passed without knowing what they are.
    e.g. max(a, b, *args) 
    4
    e.g. dict(**kwargs) (same as dict(e=5, f=6, g=7)) returns: 
    {'e': 5, 'g': 7, 'f': 6}
    

    我们还可以使用另一个函数调用它,我们只需在其中提供 a

    def bar(a):
        b, c, d, e, f = 2, 3, 4, 5, 6
        # dumping every local variable into foo as a keyword argument 
        # by expanding the locals dict:
        foo(**locals()) 
    

    bar(100) 印刷品:

    a is a required argument, and its value is 100
    b not required, its default value is 10, actual value: 2
    args is of type <type 'tuple'> and length 0
    kwargs is of type <type 'dict'> and length 4
    unknown kwarg - kw: c, arg: 3
    unknown kwarg - kw: e, arg: 5
    unknown kwarg - kw: d, arg: 4
    unknown kwarg - kw: f, arg: 6
    Args or kwargs can be passed without knowing what they are.
    e.g. max(a, b, *args) 
    100
    e.g. dict(**kwargs) (same as dict(c=3, d=4, e=5, f=6)) returns: 
    {'c': 3, 'e': 5, 'd': 4, 'f': 6}
    

    例3:在装饰中的实际使用

    好吧,也许我们还没有看到效用。因此,假设您在区分代码之前和/或之后有几个具有冗余代码的函数。为了便于说明,下面的命名函数只是伪代码。

    def foo(a, b, c, d=0, e=100):
        # imagine this is much more code than a simple function call
        preprocess() 
        differentiating_process_foo(a,b,c,d,e)
        # imagine this is much more code than a simple function call
        postprocess()
    
    def bar(a, b, c=None, d=0, e=100, f=None):
        preprocess()
        differentiating_process_bar(a,b,c,d,e,f)
        postprocess()
    
    def baz(a, b, c, d, e, f):
        ... and so on
    

    我们可能能够以不同的方式处理这个问题,但是我们当然可以使用decorator提取冗余,因此下面的示例演示了如何 *参数 非常有用:

    def decorator(function):
        '''function to wrap other functions with a pre- and postprocess'''
        @functools.wraps(function) # applies module, name, and docstring to wrapper
        def wrapper(*args, **kwargs):
            # again, imagine this is complicated, but we only write it once!
            preprocess()
            function(*args, **kwargs)
            postprocess()
        return wrapper
    

    @decorator
    def foo(a, b, c, d=0, e=100):
        differentiating_process_foo(a,b,c,d,e)
    
    @decorator
    def bar(a, b, c=None, d=0, e=100, f=None):
        differentiating_process_bar(a,b,c,d,e,f)
    
    @decorator
    def baz(a, b, c=None, d=0, e=100, f=None, g=None):
        differentiating_process_baz(a,b,c,d,e,f, g)
    
    @decorator
    def quux(a, b, c=None, d=0, e=100, f=None, g=None, h=None):
        differentiating_process_quux(a,b,c,d,e,f,g,h)
    

    通过分解我们的代码 *参数 **夸尔格斯