4

Surprising ipython magic %timeit error:

In[1]: a = 2

In[2]: %timeit a = 2 * a

Traceback (most recent call last):
  File "...\site-packages\IPython\core\interactiveshell.py", line 3326, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-97-6f70919654d1>", line 1, in <module>
    get_ipython().run_line_magic('timeit', 'a = 2 * a')
  File "...\site-packages\IPython\core\interactiveshell.py", line 2314, in run_line_magic
    result = fn(*args, **kwargs)
  File "<...\site-packages\decorator.py:decorator-gen-61>", line 2, in timeit
  File "...\site-packages\IPython\core\magic.py", line 187, in <lambda>
    call = lambda f, *a, **k: f(*a, **k)
  File "...\site-packages\IPython\core\magics\execution.py", line 1158, in timeit
    time_number = timer.timeit(number)
  File "...\site-packages\IPython\core\magics\execution.py", line 169, in timeit
    timing = self.inner(it, self.timer)
  File "<magic-timeit>", line 1, in inner
UnboundLocalError: local variable 'a' referenced before assignment

So %timeit doesn't like self re-assignment. Why? Anyway to overcome this?

Aguy
  • 7,851
  • 5
  • 31
  • 58

3 Answers3

4

As with the underlying timeit module, the timed statement is integrated into a generated function that performs the timing. The assignment to a causes the function to have an a local variable, hiding the global. It's the same issue as if you had done

a = 2

def f():
    a = 2 * a

f()

although the generated function has more code than that.

user2357112
  • 260,549
  • 28
  • 431
  • 505
2

The cell timeit with initialization works:

In [142]: %%timeit a=2 
     ...: a = 2*a 
     ...:  
     ...:                                                                       
2.68 µs ± 66.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
hpaulj
  • 221,503
  • 14
  • 230
  • 353
1

You could use some %% magic instead to avoid the assignment error:

%%timeit
a = 2
a = a*2
FObersteiner
  • 22,500
  • 8
  • 42
  • 72
  • 1
    That's not how `%timeit` works. You're timing the creation of a 2-element tuple containing two strings, rather than performing `s` as setup and timing the execution of `c`. – user2357112 Sep 30 '19 at 08:53
  • @user2357112: just realised that! thanks for the comment! – FObersteiner Sep 30 '19 at 08:57