timeit ValueError: stmt не является ни строкой, ни вызываемой - PullRequest
0 голосов
/ 10 января 2019

Я играл с timeit в Python, возникла странная проблема.

Я определяю простую функцию add. timeit работает, когда я передаю add два строковых параметра. Но он поднимает ValueError: stmt is neither a string nor callable, когда я передаю add два int параметра.

>>> import timeit
>>> def add(x,y):
...     return x + y
... 


>>> a = '1'
>>> b = '2'
>>> timeit.timeit(add(a,b))
0.01355926995165646


>>> a = 1
>>> b = 2
>>> timeit.timeit(add(a,b))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/anaconda/lib/python3.6/timeit.py", line 233, in timeit
    return Timer(stmt, setup, timer, globals).timeit(number)
  File "/anaconda/lib/python3.6/timeit.py", line 130, in __init__
    raise ValueError("stmt is neither a string nor callable")
ValueError: stmt is neither a string nor callable

Почему тип параметра здесь вообще имеет значение?

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Ваша ошибка в том, что Python передает выражение add(a, b) в timeit(). Это не так, add(a, b) не является строкой, это выражение, поэтому Python вместо выполняет add(a, b) и результат этого вызова передается в вызов timeit() .

Таким образом, для add('1', '2') результат будет '12', строка. Передача строки в timeit() это нормально. Но add(1, 2) - это 12, целое число. timeit(12) дает вам исключение. Конечно, не то, чтобы время '12' было таким интересным, но это допустимое выражение Python, которое выдает целочисленное значение 12:

>>> import timeit
>>> def add(x,y):
...     return x + y
...
>>> a = '1'
>>> b = '2'
>>> add(a, b)
'12'
>>> timeit.timeit('12')
0.009553937998134643
>>> a = 1
>>> b = 2
>>> add(a, b)
12
>>> timeit.timeit(12)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/.../lib/python3.7/timeit.py", line 232, in timeit
    return Timer(stmt, setup, timer, globals).timeit(number)
  File "/.../lib/python3.7/timeit.py", line 128, in __init__
    raise ValueError("stmt is neither a string nor callable")
ValueError: stmt is neither a string nor callable

Это все совершенно нормально; в противном случае, как вы могли бы передать результат функции другой функции напрямую? timeit.timeit() - это просто еще одна функция Python , ничего особенного, что она отключит нормальную оценку выражений.

Вам нужно передать строку с выражением в timeit(). timeit() не имеет доступа к вашей функции add(), или a, или b, поэтому вам нужно предоставить ему доступ со вторым аргументом, строкой установки. Вы можете использовать from __main__ import add, a, b для импорта функционального объекта ad:

timeit.timeit('add(a,b)', 'from __main__ import add, a, b')

Теперь вы получаете более значимые результаты:

>>> import timeit
>>> def add(x,y):
...     return x + y
...
>>> a = '1'
>>> b = '2'
>>> timeit.timeit('add(a,b)', 'from __main__ import add, a, b')
0.16069997000158764
>>> a = 1
>>> b = 2
>>> timeit.timeit('add(a,b)', 'from __main__ import add, a, b')
0.10841095799696632

Таким образом, добавление целых чисел происходит быстрее, чем добавление строк. Возможно, вы захотите попробовать это с разными размерами целых чисел и строк, но добавление целых чисел останется более быстрым результатом.

0 голосов
/ 10 января 2019

мой вопрос, почему здесь важен тип параметра?

Аргументы функции полностью оцениваются перед вызовом функции. Это означает, что когда вы делаете:

timeit.timeit(add(a,b))

Тогда add(a,b) уже вычислено до использования timeit. Так что времени не имеет.

Причина, по которой timeit.timeit(add(a,b)) "работает", когда a и b являются числовыми строками, является просто глупой: это время оценки '12'. Результатом вызова add('1', '2') является допустимая строка кода Python. timeit компилирует его и предполагает, что вы хотите рассчитать время вычисления буквального целого числа 12.

...