2015-03-11 2 views
3

Fauler's Extract Variable метод рефакторинга, ранее Introduce Explaining Variable, говорит, что используется временная переменная, чтобы сделать код более понятным для людей. Идея состоит в том, чтобы прояснить сложный код, введя ненужную локальную переменную в противном случае и обозначив эту переменную для целей изложения. Он также выступает за такое объяснение комментариев. Other languages оптимизируйте временные переменные, чтобы не было затрат во времени или космических ресурсах. Почему Python не делает этого?Почему Python не оптимизирует временные переменные?

 
In [3]: def multiple_of_six_fat(n): 
    ...:  multiple_of_two = n%2 == 0 
    ...:  multiple_of_three = n%3 == 0 
    ...:  return multiple_of_two and multiple_of_three 
    ...: 

In [4]: def multiple_of_six_lean(n): 
    ...:  return n%2 == 0 and n%3 == 0 
    ...: 
 
In [5]: import dis 

In [6]: dis.dis(multiple_of_six_fat) 
    2   0 LOAD_FAST    0 (n) 
       3 LOAD_CONST    1 (2) 
       6 BINARY_MODULO 
       7 LOAD_CONST    2 (0) 
      10 COMPARE_OP    2 (==) 
      13 STORE_FAST    1 (multiple_of_two) 

    3   16 LOAD_FAST    0 (n) 
      19 LOAD_CONST    3 (3) 
      22 BINARY_MODULO 
      23 LOAD_CONST    2 (0) 
      26 COMPARE_OP    2 (==) 
      29 STORE_FAST    2 (multiple_of_three) 

    4   32 LOAD_FAST    1 (multiple_of_two) 
      35 JUMP_IF_FALSE_OR_POP 41 
      38 LOAD_FAST    2 (multiple_of_three) 
     >> 41 RETURN_VALUE 

In [7]: dis.dis(multiple_of_six_lean) 
    2   0 LOAD_FAST    0 (n) 
       3 LOAD_CONST    1 (2) 
       6 BINARY_MODULO 
       7 LOAD_CONST    2 (0) 
      10 COMPARE_OP    2 (==) 
      13 JUMP_IF_FALSE_OR_POP 29 
      16 LOAD_FAST    0 (n) 
      19 LOAD_CONST    3 (3) 
      22 BINARY_MODULO 
      23 LOAD_CONST    2 (0) 
      26 COMPARE_OP    2 (==) 
     >> 29 RETURN_VALUE 

ответ

9

Поскольку Python является очень динамическим языком, и ссылки могут влиять на поведение.

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

>>> id(object()) == id(object()) 
True 
>>> ob1 = object() 
>>> ob2 = object() 
>>> id(ob1) == id(ob2) 
False 

Имел Python 'оптимизированной' в ob1 и ob2 переменные прочь, поведение изменилось бы.

Срок службы объекта Python определяется подсчетом ссылок. Добавьте weak references в микс плюс потоки, и вы увидите, что оптимизация переменных (даже локальных) может привести к нежелательным изменениям поведения.

Кроме того, в Python удаление этих переменных вряд ли изменит что-либо с точки зрения производительности. Локальное пространство имен уже сильно оптимизировано (значения просматриваются индексом в массиве); если вас беспокоит скорость разыменования локальных переменных, вы используете неправильный язык программирования для этого важного раздела вашего проекта.

+1

Хороший простой пример, но интересно, есть ли тот, который больше похож на функцию, чем на ошибку. Это подрывает ваш аргумент, чтобы сказать, что они должны давать разные результаты. –

+0

@ BobStein-VisiBone: это один пример ** поведения, который иллюстрирует, почему связывают вопросы. Их гораздо больше, но они занимают больше времени, чтобы строить и объяснять. –

+0

@ BobStein-VisiBone: дело в том, что функция существует, и если Python должен был решить, что «ob1» и «ob2» можно оптимизировать, тогда у вас будет ошибка, потому что поведение изменится, когда вы это сделаете. –

2

Issue 2181 (оптимизации из локальных переменных в конце функции) имеет некоторые интересные моменты:

  • Это может сделать не отладки сложнее, так как символы больше не существует. Guido says only do it for -O.
  • Возможны обмены некоторых видов использования inspect или sys._getframe().
  • Изменяет срок службы объектов. Например, myfunc в следующем примере может выйти из строя после оптимизации, поскольку на данный момент Python гарантирует, что объект файла не будет закрыт до выхода функции. (Плохой стиль, но все же)

    def myfunc(): 
        f = open('somewhere', 'r') 
        fd = f.fileno() 
        return os.fstat(fd) 
    

    не может быть переписано в виде:

    def bogus(): 
        fd = open('somewhere', 'r').fileno() 
        # the file is auto-closed here and fd becomes invalid 
        return os.fstat(fd) 
    
  • разработчик ядра говорит, что «вряд ли даст какой-либо прирост скорости в реальном коде, я не думаю, мы должны добавить сложность в компилятор ».

Смежные вопросы