Наблюдение:
>>> def costly():
... return list(map(str, list(range(1_000_000))))
...
>>> timeit.timeit(costly, number=100)
30.65105245400082
>>> timeit.timeit('costly', number=1_000_000_000, globals=globals())
27.45540758000061
Посмотрите на аргумент number
. потребовалось 30 секунд для выполнения функции costly
100 раз. потребовалось почти 30 секунд, чтобы выполнить выражение costly
1'000'000'000 (!) Раз.
Почему?Поскольку второй код не не выполняет функцию costly
!Единственное, что он выполняет, это выражение costly
: обратите внимание на отсутствие скобок, что означает, что это , а не вызов функции.Выражение costly
в основном не работает (ну, это просто требует проверки, существует ли имя «дорогой» в текущей области, вот и все), поэтому это так быстро, и если Python был достаточно умен, чтобы оптимизировать еговыполнение выражения costly
( не costly()
!) было бы мгновенным!
В вашем случае выражение lambda *args: None
просто определяет anанонимная функция, верно?Когда вы выполняете этот точный код , новая функция создается, но не выполняется (для этого вам нужно вызвать it: (lambda *args: None)()
).
Таким образом, синхронизация строки "lambda *args: None"
с timeit.timeit("lambda *args: None")
в основном проверяет, насколько быстро Python может выплевывать новые анонимные функции.
Время самой функции с timeit.timeit(lambda *args: None)
проверяет, насколько быстро Python может выполнить * существующую функцию.
Выделение вновь созданных функций - это просто, а на самом деле их запуск может быть очень сложным.
Возьмите этот код, например:
def Ackermann(m, n):
if m == 0:
return n + 1
if m > 0:
if n == 0:
return Ackermann(m - 1, 1)
elif n > 0:
return Ackermann(m - 1, Ackermann(m, n - 1))
Если вы поместите этот точный код в строку и timeit
его, вы получите что-то вроде этого:
>>> code = """def Ackermann(m, n):
... if m == 0:
... return 0
... if m > 0:
... if n == 0:
... return Ackermann(m - 1, 1)
... elif n > 0:
... return Ackermann(m - 1, Ackermann(m, n - 1))"""
>>> timeit.timeit(code, number=1_000_000)
0.10481472999890684
Теперь попробуйте timeit
саму функцию:
>>> timeit.timeit(lambda : Ackermann(6, 4), number=1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/timeit.py", line 232, in timeit
return Timer(stmt, setup, timer, globals).timeit(number)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/timeit.py", line 176, in timeit
timing = self.inner(it, self.timer)
File "<timeit-src>", line 6, in inner
File "<stdin>", line 1, in <lambda>
File "<stdin>", line 8, in Ackermann
File "<stdin>", line 8, in Ackermann
File "<stdin>", line 8, in Ackermann
[Previous line repeated 1 more time]
File "<stdin>", line 6, in Ackermann
File "<stdin>", line 8, in Ackermann
File "<stdin>", line 6, in Ackermann
File "<stdin>", line 8, in Ackermann
File "<stdin>", line 8, in Ackermann
File "<stdin>", line 8, in Ackermann
[Previous line repeated 983 more times]
File "<stdin>", line 6, in Ackermann
File "<stdin>", line 2, in Ackermann
RecursionError: maximum recursion depth exceeded in comparison
Смотрите - вы даже не можете запустить это!На самом деле, вероятно, никто не может, так как это так много рекурсии!
Почему первый вызов прошел успешно?Поскольку он ничего не выполнял, он просто выплевывал множество новых функций и вскоре избавлялся от всех них.