概述
Why does this happen? Should I avoid specifying argument values during calls?
一般来说,没有.你能够看到的真正原因是因为你使用的功能并不是计算密集型的.因此,可以通过定时检测在提供参数的情况下发出的附加字节代码命令所需的时间.
例如,如果你有一个更加密集的形式的功能:
def foo_intensive(a=10, b=20, c=30, d=40):
[i * j for i in range(a * b) for j in range(c * d)]
它几乎不会显示任何时间的差异:
%timeit foo_intensive()
10 loops, best of 3: 32.7 ms per loop
%timeit foo_intensive(a=10, b=20, c=30, d=40)
10 loops, best of 3: 32.7 ms per loop
即使扩展到更多的呼叫,执行功能体所需的时间也可以简化占用额外字节码指令引入的小开销.
查看字节码:
查看为每个调用情况发出的生成的字节码的一种方法是创建一个围绕foo并以不同方式调用它的函数.现在,让我们使用默认参数为fooDefault创建调用,fooKwargs()用于指定关键字参数的函数:
# call foo without arguments, using defaults
def fooDefault():
foo()
# call foo with keyword arguments
def fooKw():
foo(a=10, b=20, c=30, d=40)
现在有了dis,我们可以看到这些之间的字节码的差异.对于默认版本,我们可以看到基本上发出一个命令(忽略在两种情况下都存在的POP_TOP)用于函数调用,CALL_FUNCTION:
dis.dis(fooDefaults)
2 0 LOAD_GLOBAL 0 (foo)
3 CALL_FUNCTION 0 (0 positional, 0 keyword pair)
6 POP_TOP
7 LOAD_CONST 0 (None)
10 RETURN_VALUE
另一方面,在使用关键字的情况下,发出另外8个LOAD_CONST命令,以将参数名称(a,b,c,d)和值(10,20,30,40)加载到值堆栈(即使加载数字<256在这种情况下可能非常快,因为它们被缓存):
dis.dis(fooKwargs)
2 0 LOAD_GLOBAL 0 (foo)
3 LOAD_CONST 1 ('a') # call starts
6 LOAD_CONST 2 (10)
9 LOAD_CONST 3 ('b')
12 LOAD_CONST 4 (20)
15 LOAD_CONST 5 ('c')
18 LOAD_CONST 6 (30)
21 LOAD_CONST 7 ('d')
24 LOAD_CONST 8 (40)
27 CALL_FUNCTION 1024 (0 positional, 4 keyword pair)
30 POP_TOP # call ends
31 LOAD_CONST 0 (None)
34 RETURN_VALUE
另外,关键字参数不为零的情况通常需要一些额外的步骤. (例如ceval/_PyEval_EvalCodeWithName()).
即使这些命令真的很快,他们总结一下.参数越多,总和越大,当许多调用函数实际执行时,这些堆积将导致执行时间的差异.
这些的直接结果是,我们指定的值越多,必须发出的命令越多,函数的运行速度越慢.此外,指定位置参数,解包位置参数和解包关键字参数都具有与它们相关的不同开销:
>位置参数foo(10,20,30,40):需要4个附加命令来加载每个值.
>列出解包foo(* [10,20,30,40]):4个LOAD_CONST命令和一个附加的BUILD_LIST命令.
>使用foo(* l)中的列表可以减少执行,因为我们提供了一个包含值的已经建立的列表.
>字典解包foo(** {‘a’:10,’b’:20,’c’:30,’d’:40}):8 LOAD_CONST命令和BUILD_MAP.
与列表解压缩foo(** d)一样,由于内置的列表将被提供,因此将会执行程序.
所有在不同情况下的呼叫执行时间的所有订单是:
defaults < positionals < keyword arguments < list unpacking < dictionary unpacking
我建议在这些情况下使用dis.dis,看看他们的区别.
结论是:
正如@goofd在评论中指出的,这真的是一个不用担心的事情,它确实取决于用例.如果您从计算的角度经常调用“光”功能,则指定默认值会稍微提高速度.如果你经常提供不同的值,那么这个值就不会产生.
所以,这可能是微不足道的,并试图从晦涩的边缘案例中获得提升,因为这真的是推动它.如果你发现自己这样做,你可能想看看像PyPy和Cython这样的事情.
最后
以上就是义气纸鹤为你收集整理的python函数被调用才能执行吗_python – 为什么无争论的函数调用执行得更快?的全部内容,希望文章能够帮你解决python函数被调用才能执行吗_python – 为什么无争论的函数调用执行得更快?所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复