Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/348.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 函数调用中*args的执行模型是什么?_Python_Function - Fatal编程技术网

Python 函数调用中*args的执行模型是什么?

Python 函数调用中*args的执行模型是什么?,python,function,Python,Function,我需要传递巨大的列表/元组,以便通过*args运行 def f(*args): # defined in foreign module pass arguments = tuple(range(10000)) f(*arguments) 我想知道函数调用时会发生什么 它是否处理类似于任何位置变量的参数:在body执行期间保存它并按需访问?或者它甚至在主体执行之前就迭代参数,扩展位置参数?还是其他原因?使用发电机的简单测试: def gen(): print('Yieldin

我需要传递巨大的
列表
/
元组
,以便通过
*args
运行

def f(*args):  # defined in foreign module
    pass

arguments = tuple(range(10000))
f(*arguments)
我想知道函数调用时会发生什么


它是否处理类似于任何位置变量的
参数
:在body执行期间保存它并按需访问?或者它甚至在主体执行之前就迭代
参数
,扩展位置参数?还是其他原因?

使用发电机的简单测试:

def gen():
    print('Yielding 1')
    yield 1
    print('Yielding 2')
    yield 2
    print('Yielding 3')
    yield 3


arguments = gen()
def f(*args):
    pass

f(*arguments)
# Yielding 1
# Yielding 2
# Yielding 3
从输出中可以看到,传递
*参数实际上会解压整个iterable,因为从技术上讲,您是在告诉Python使用
*参数
语法将iterable作为单个参数传递。函数定义也使用
*args
,这使得Python再次将参数打包回元组,这并不重要


所以,是的,你打开列表只是为了在这里再次打包。您可以通过直接传递列表来避免这种情况。

是的,
*arguments
调用语法必须迭代
arguments
iterable,原因有两个:

  • 您正在传入一个列表,但函数中的变量大小参数是元组。所以元素必须复制到这里

  • 调用语法必须适用于任何函数,其中您可能有实际的位置参数,而不是
    *varargs
    变量,或者除此之外还有
    *varargs
    变量

    例如,如果函数签名是
    def(foo,*args):
    ,则必须单独传入第一个元素

    原则上,CPython可以优化在调用
    函数(*tupleargs)
    时使用的元组的所有值都以
    *varargs
    参数结尾的情况,并重新使用该元组。然而,这实际上并不是那么普遍,也没有人这样做


注意,对于
**kwargs
调用语法,增加的可变性挑战使得共享使用的对象成为一个非常糟糕的主意;您必须创建所用dict的副本,因为否则函数或调用方可能会使用其他引用中反映的更改对该字典进行变异。

因为
参数
是一个列表,而
参数
是一个元组,是的,必须进行迭代。并不是说在这里将
参数
设置为元组会有所帮助。您可以尝试通过编写一个自定义对象来测试这一点,该对象会告诉您何时对其进行迭代。因此,即使
参数
是元组,也会发生此迭代?@Ormazd yes。同样的原理也适用于关键字参数,即创建一个新的
dict
。您必须记住,Python作为一种动态语言,在解释调用时不知道
f
使用变量参数。所以它只能在事后处理,所以你可能需要建立很多额外的逻辑。根本不存在的逻辑,因为实际上不需要进一步优化。实际上,您并没有向函数传递数百个参数。在调用中使用元组时(例如,
*(1,2,3)
),可能不会迭代元组,因为值最终会出现在函数中的
*args
变量中,但Python不会进行此类优化。