ipython%timeit“局部变量'a'在赋值前引用”

时间:2018-01-15 19:47:06

标签: python ipython timeit

我正在尝试运行以下代码,但我得到了local variable 'a' referenced before assignment.

a = [x for x in range(10)]
b = [x for x in range(10)]
%timeit a+=b

该声明在没有%timeit魔法的情况下起作用。

我有什么遗失的吗?

谢谢。

1 个答案:

答案 0 :(得分:3)

您期望它做什么?

超出时间范围:

In [188]: a += b
In [189]: a
Out[189]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

我尝试初始化x,并且接近无限循环,最终以内存错误结束

In [192]: %%timeit x=a
     ...: x += b

In [194]: len(a)
Out[194]: 529076630

换句话说,每个timeit循环将b值的另一个列表连接到x(并通过扩展名a),结果是非常长的循环。我怀疑某个人x+=b速度很快,导致timeit选择多次循环。

让我们创建一个a新的每个循环:

In [196]: %%timeit
     ...: a = [x for x in range(10)]
     ...: a += b
     ...: 
1.91 µs ± 4.82 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

这也会产生内存错误:

In [197]: %%timeit a = [x for x in range(10)]
     ...: a += b

如果我控制循环次数:

In [202]: %%timeit -n 100 a = [x for x in range(10)]
     ...: a += b
     ...: 
     ...: 
208 ns ± 11 ns per loop (mean ± std. dev. of 7 runs, 100 loops each)

ns次,我可以看到为什么默认循环如此之大。

我还没有尝试过普通的a+=...计时(甚至没有numpy数组),但显然它期望在a内进行某种局部初始化,无论是在循环内还是在初始化块。但重要的是要记住,定时动作可以执行多次(-r和-n参数或默认值)。因此,任何就地操作都可能导致对全局值的位更改。在这种情况下,timeit可能会试图保护我们免受这种意外增长的影响,因为期待某种“本地化”。变量

让我们试试a+b,但有一项作业:

In [215]: c=np.zeros(10)
In [216]: a
Out[216]: array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10])
In [217]: b
Out[217]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [218]: %timeit c = a+b
5.33 µs ± 105 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [219]: c
Out[219]: array([ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.])

请注意,全局c尚未更改。分配到临时本地c - 即使可以使用同名的全局。

作为一般规则,在定时循环内执行的计算不应泄漏到循环外部。你必须像我在内存错误循环中所做的那样明确,或者这里

In [222]: %%timeit x = c
     ...: x += b
     ...: 
9.04 µs ± 238 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [223]: c
Out[223]: 
array([       0.,   811111.,  1622222.,  2433333.,  3244444.,  4055555.,
        4866666.,  5677777.,  6488888.,  7299999.])

或在这里:

In [224]: c=np.zeros(10)
In [225]: %%timeit x = c
     ...: x[:] = a+b

7.84 µs ± 199 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [226]: c
Out[226]: array([  1.,   3.,   5.,   7.,   9.,  11.,  13.,  15.,  17.,  19.])

两者都使用就地变量进行就地分配,该变量已链接到可变全局变量。