Подтвердить что ты не робот

Python интерпретирует оптимизацию кода

Рассмотрим следующий фрагмент кода:

dict [name] = 0
dict [name] += 1
dict [name] += 1

Является ли интерпретатор python автоматически распознавать повторяющиеся ссылки на значение словаря и вместо этого использует вместо этого кешированную локальную ссылку?, что несколько напоминает оптимизацию сглаживания C/С++, что-то вроде этого:

value = dict [name]
value = 0
value += 1
value += 1

Очевидно, это не очень важно сделать это вручную, но мне любопытно, действительно ли это необходимо. любое понимание, отзывы и т.д..

4b9b3361

Ответ 1

Вы можете запустить его через дизассемблер, чтобы узнать:

import dis

def test():
    name = 'test'
    tdict = {}
    tdict[name] = 0
    tdict[name] += 1
    tdict[name] += 1

dis.dis(test)

Запустив это, получим:

 13           0 LOAD_CONST               1 ('test')
              3 STORE_FAST               0 (name)

 14           6 BUILD_MAP                0
              9 STORE_FAST               1 (tdict)

 15          12 LOAD_CONST               2 (0)
             15 LOAD_FAST                1 (tdict)
             18 LOAD_FAST                0 (name)
             21 STORE_SUBSCR        

 16          22 LOAD_FAST                1 (tdict)
             25 LOAD_FAST                0 (name)
             28 DUP_TOPX                 2
             31 BINARY_SUBSCR       
             32 LOAD_CONST               3 (1)
             35 INPLACE_ADD         
             36 ROT_THREE           
             37 STORE_SUBSCR        

 17          38 LOAD_FAST                1 (tdict)
             41 LOAD_FAST                0 (name)
             44 DUP_TOPX                 2
             47 BINARY_SUBSCR       
             48 LOAD_CONST               3 (1)
             51 INPLACE_ADD         
             52 ROT_THREE           
             53 STORE_SUBSCR        
             54 LOAD_CONST               0 (None)
             57 RETURN_VALUE        

Похоже, что в этом случае LOAD_FAST загружает значения tdict и name каждый раз, когда мы пытаемся получить к нему доступ для выполнения приращения, поэтому ответ будет выглядеть как нет.

Ответ 2

Этот тип оптимизации невозможно просто путем проверки кода. Ваше имя dict может ссылаться не на родной словарь, а на определенный пользователем объект, который реализует __setitem__, и этот метод нужно вызывать три раза. Во время выполнения сложная реализация может отметить фактическое значение имени и сделать оптимизацию, но она не может быть выполнена до выполнения, не нарушая семантики Python.

Ответ 3

Нет, потому что это не сработает, и вы даже продемонстрировали, что с вашим собственным кодом - это фактически не эквивалентно:

>>> a = {}
>>> name = 'x'
>>> a[name] = 0
>>> a[name] += 1
>>> a[name] += 1
>>> a[name] # ok no suprises so far
2
>>> a = {}
>>> a[name] = 0
>>> x = a[name] # x is now literally `0`, not some sort of reference to a[name]
>>> x
0
>>> x += 1
>>> x += 1
>>> a[name] # so this never changed
0
>>>

Python не имеет ссылок на C-ish. То, что вы имели в виду, будет работать только для изменяемых типов, таких как list. Это очень фундаментальное свойство Python, и вы, вероятно, должны забыть все, что C научил вас переменным при программировании Python.

Ответ 4

Измените два примера на следующее:

#v1.py
di = {}
name = "hallo"
di[name] = 0
for i in range(2000000):
    di[name] += 1

и

#v2.py
di = {}
name = "hallo"
di[name] = 0
value = di[name]
for i in range(2000000):
    value += 1

В следующих тестах вы можете увидеть, что v2 быстрее, но pypy выполняется намного быстрее: -)

$ time python2.7 v1.py
real    0m0.788s
user    0m0.700s
sys     0m0.080s

$ time python2.7 v2.py
real    0m0.586s
user    0m0.490s
sys     0m0.090s

$ time pypy v1.py
real    0m0.203s
user    0m0.210s
sys     0m0.000s

$ time pypy v2.py
real    0m0.117s
user    0m0.080s
sys     0m0.030s

SO: нехорошо оптимизировать код для одного интерпретатора (например, я не тестировал Jython...), но это здорово, когда кто-то оптимизирует интерпретатор...