在 Python 3.9 中,嵌套函数比普通函数慢得多,在我的例子中大约是 10%。
from timeit import timeit
def f():
return 0
def factory():
def g():
return 0
return g
g = factory()
print(timeit("f()", globals=globals()))
#> 0.074835498
print(timeit("g()", globals=globals()))
#> 0.08470309999999998
dis.dis
显示相同的字节码,我发现的唯一区别在于函数内部标志。实际上,dis.show_code
表明 g
有标志 NESTED
而 f
没有。
然而,标志可以被移除,它使 g
和 f
一样快。
import inspect
g.__code__ = g.__code__.replace(co_flags=g.__code__.co_flags ^ inspect.CO_NESTED)
print(timeit("f()", globals=globals()))
#> 0.07321161100000001
print(timeit("g()", globals=globals()))
#> 0.07439838800000001
我试图查看 CPython 代码以了解 CO_NESTED
标志如何影响函数执行,但我一无所获。对于与 CO_NESTED
标志相关的这种性能差异,是否有任何解释?
EDIT:删除 CO_NESTED
标志似乎对函数执行也没有影响,除了开销,即使它捕获了变量。
import inspect
global_var = 40
def factory():
captured_var = 2
def g():
return global_var + captured_var
return g
g = factory()
assert g() == 42
g.__code__ = g.__code__.replace(co_flags=g.__code__.co_flags ^ inspect.CO_NESTED)
assert g() == 42 # function still works as expected
答案 0 :(得分:1)
我可能错了,但我认为不同之处在于,g
可以潜在地引用 factory
的局部变量,因此需要访问两个范围以进行任何变量查找: globals
和 factory
。保护这个额外的作用域(或从 factory
和 globals
合并作用域)很可能是您观察到的开销的原因。一个很好的提示是,如果您嵌套另一个级别的函数:
def factory():
def ff():
def g():
return 0
return g
return ff()
g = factory() # please note that it is equivalent from the perspective of time measurement
时间:
print(timeit("f()", globals=globals(), number=100000000))
# > 6.792911
print(timeit("g()", globals=globals(), number=100000000))
# > 7.8184555
在你的第一个计时案例中,我得到了 +5.7%(你的数字是 +13.5%),在我的第二个例子中:+15.1%。