Время присваивать переменную в Python - PullRequest
0 голосов
/ 26 июня 2018

Предположим, у меня в очень тесном цикле следующее:

a = func(x)
b = func2(a)

Переменная a больше нигде не используется.

Python автоматически компилирует присваивание для a, или требуется время для выполнения присваивания переменной каждый раз? Другими словами, идентичен ли этот код или он немного быстрее из-за отсутствия присваивания a?

b = func2(func(x))

Одинаково ли поведение Python2.7 и Python3?

Ответы [ 4 ]

0 голосов
/ 26 июня 2018

Фактическое время будет зависеть от функций func() и func2() do. Не лучший пример, но быстрый (и грязный) тестовый код приведен ниже:

import time

def func(x):
    return 5

def func2(a):
    return 10

t0 = time.time()
x = 10
for i in range(1,10000):
    a = func(x)
    b = func2(a)
t1 = time.time()

print("Time 1: ", t1-t0)

t2 = time.time()
x = 10
for i in range(1,10000):
    b = func2(func(x))
t3 = time.time()

print("Time 2: ", t3-t2)

Вывод вышеуказанного кода:

Time 1:  0.0029211044311523438
Time 2:  0.002785921096801758

Так что да, реализация, в которой мы избегаем присвоения a, немного быстрее в Pyhton 3.

0 голосов
/ 26 июня 2018

Итак, используя очень забавный модуль dis, мы можем посмотреть фактический байт-код, сгенерированный из предоставленного вами кода Python. Для простоты я заменил func и func2 на встроенные функции (int и float).

Итак, наш источник выглядит так:

def assign():
    a = int()
    b = float(a)

По сравнению с упрощенной версией:

def simple():
    b = float(int())

И затем, начиная с интерпретатора cpython 2.7, мы можем увидеть байт-коды, сгенерированные из функции assign:

dis.dis(assign)
  2           0 LOAD_GLOBAL              0 (int)
              3 CALL_FUNCTION            0
              6 STORE_FAST               0 (a)

  3           9 LOAD_GLOBAL              1 (float)
             12 LOAD_FAST                0 (a)
             15 CALL_FUNCTION            1
             18 STORE_FAST               1 (b)
             21 LOAD_CONST               0 (None)
             24 RETURN_VALUE

Как вы можете видеть, оптимизация глазка не позволяет удалить ненужную промежуточную переменную, что приводит к дополнительным 2 инструкциям (STORE_FAST a, LOAD_FAST a) при сравнении с байт-кодами для упрощенного `простого метода:

dis.dis(simple)
  2           0 LOAD_GLOBAL              0 (float)
              3 LOAD_GLOBAL              1 (int)
              6 CALL_FUNCTION            0
              9 CALL_FUNCTION            1
             12 STORE_FAST               0 (b)
             15 LOAD_CONST               0 (None)
             18 RETURN_VALUE

Это то же самое для интерпретатора CPython для Python 3.5 и для интерпретатора pypy для Python 2.7.

0 голосов
/ 26 июня 2018

Используйте модуль dis для сравнения байт-кода: похоже, что второй метод производит меньше операций

import dis

print(dis.dis('a=f(2);b=g(a)'))
print(dis.dis('b=g(f(2))'))


>>>   
  1           0 LOAD_NAME                0 (f)
              2 LOAD_CONST               0 (2)
              4 CALL_FUNCTION            1
              6 STORE_NAME               1 (a)
              8 LOAD_NAME                2 (g)
             10 LOAD_NAME                1 (a)
             12 CALL_FUNCTION            1
             14 STORE_NAME               3 (b)
             16 LOAD_CONST               1 (None)
             18 RETURN_VALUE
None
  1           0 LOAD_NAME                0 (g)
              2 LOAD_NAME                1 (f)
              4 LOAD_CONST               0 (2)
              6 CALL_FUNCTION            1
              8 CALL_FUNCTION            1
             10 STORE_NAME               2 (b)
             12 LOAD_CONST               1 (None)
             14 RETURN_VALUE
None
0 голосов
/ 26 июня 2018

Такой тип запросов может быть легко проверен с помощью timeit. Вот результаты с Python2.7.

root:/var# python -m timeit "f1 = lambda x:x; f2 = lambda x: x*2; a=f1(2); b=f2(a)"
1000000 loops, best of 3: 0.29 usec per loop
root:/var# python -m timeit "f1 = lambda x:x; f2 = lambda x: x*2; b=f2(f1(2))"
1000000 loops, best of 3: 0.284 usec per loop
root:/var# python -m timeit "f1 = lambda x:x; f2 = lambda x: x*2; a=f1(2); b=f2(a)"
1000000 loops, best of 3: 0.285 usec per loop
root:/var# python -m timeit "f1 = lambda x:x; f2 = lambda x: x*2; b=f2(f1(2))"
1000000 loops, best of 3: 0.283 usec per loop
root:/var# python -m timeit "f1 = lambda x:x; f2 = lambda x: x*2; a=f1(2); b=f2(a)"
1000000 loops, best of 3: 0.294 usec per loop
root:/var# python -m timeit "f1 = lambda x:x; f2 = lambda x: x*2; b=f2(f1(2))"
1000000 loops, best of 3: 0.286 usec per loop

И это показывает непротиворечивые результаты с другими ответами, которые описывают использование удивительного dis модуля.

...