Итак, вчера я усвоил трудный путь, что:
s = []
for i in range(n):
s.append('a')
"".join(s)
сильно *, значительно отличается от приведенного ниже, с точки зрения скорости (несмотря на то, что оба имеют одинаковую "временную сложность"")
'a' * n
Причина почти очевидна: первый вызывает (относительно) слишком много вызовов ассемблера.
>>> import dis
>>> def f(c,n):
... return c*n
...
>>> def f2(c,n):
... l = []
... for i in range(n):
... l.append(c)
...
>>> dis.dis(f)
2 0 LOAD_FAST 0 (c)
2 LOAD_FAST 1 (n)
4 BINARY_MULTIPLY
6 RETURN_VALUE
>>> dis.dis(f2)
2 0 BUILD_LIST 0
2 STORE_FAST 2 (l)
3 4 SETUP_LOOP 26 (to 32)
6 LOAD_GLOBAL 0 (range)
8 LOAD_FAST 1 (n)
10 CALL_FUNCTION 1
12 GET_ITER
>> 14 FOR_ITER 14 (to 30)
16 STORE_FAST 3 (i)
4 18 LOAD_FAST 2 (l)
20 LOAD_METHOD 1 (append)
22 LOAD_FAST 0 (c)
24 CALL_METHOD 1
26 POP_TOP
28 JUMP_ABSOLUTE 14
>> 30 POP_BLOCK
>> 32 LOAD_CONST 0 (None)
34 RETURN_VALUE
Мой вопрос: что это за другие примеры такого рода кода, где два фрагмента, имеющие одинаковую временную сложность, работают с очень разными скоростями?
(извиняюсь и понимаю, если это немного не по темеПросто сейчас я потерял собеседование, не зная о пустяках, описанных выше. Я не могу позволить, чтобы такие вещи повторялись, поэтому я сделал этот пост, частично из-за разочарования)