【发布时间】:2017-12-23 23:03:51
【问题描述】:
请原谅 Python 爱好者一个主要是学术问题。
我对嵌套函数的成本(如果有的话)感兴趣 - 不是利用闭包等的功能合理的函数,而是保持外部命名空间整洁的多样性。
所以我做了一个简单的测量:
def inner(x):
return x*x
def flat(x):
return inner(x)
def nested(x):
def inner(x):
return x*x
return inner(x)
# just to get a feel of the cost of having two more lines
def fake_nested(x):
y = x
z = x
return inner(x)
from timeit import timeit
print(timeit('f(3)', globals=dict(f=flat)))
print(timeit('f(3)', globals=dict(f=nested)))
print(timeit('f(3)', globals=dict(f=fake_nested)))
# 0.17055258399341255
# 0.23098028398817405
# 0.19381927204085514
所以似乎有一些开销,而且似乎比多两行来解释的要多。
然而,似乎每次调用外部函数时都不会评估内部 def 语句,实际上内部函数对象似乎已被缓存:
def nested(x):
def inner(x):
return x*x
print(id(inner), id(inner.__code__), id(inner.__closure__))
return inner(x)
nested(3)
x = [list(range(i)) for i in range(5000)] # create some memory pressure
nested(3)
# 139876371445960 139876372477824 8845216
# 139876371445960 139876372477824 8845216
寻找其他可能会增加运行时间的东西我偶然发现了以下书呆子:
def nested(x):
def inner(x):
return x*x
print(id(inner), id(inner.__code__), id(inner.__closure__))
return inner
nested(3)
x = [list(range(i)) for i in range(5000)] # create some memory pressure
a = nested(3)
x = [list(range(i)) for i in range(5000)] # create some memory pressure
nested(3)
# 139906265032768 139906264446704 8845216
# 139906265032768 139906264446704 8845216
# 139906264258624 139906264446704 8845216
似乎如果 Python 检测到缓存的嵌套函数有外部引用,那么它会创建一个新的函数对象。
现在 - 假设到目前为止我的推理还没有完全偏离 - 我的问题:这有什么好处?
我的第一个想法是“好吧,如果用户有对缓存函数的引用,他们可能已经搞砸了,所以最好创建一个干净的新函数。”但是再想想似乎并没有被洗掉,因为副本不是深层副本,如果用户弄乱了函数然后扔掉了引用怎么办?
补充问题:Python 是否在幕后做了任何其他极其聪明的事情?与嵌套相比,这与嵌套的执行速度慢有关吗?
【问题讨论】:
标签: python function nested copy-on-write