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

Являются ли постоянные вычисления кэшированными в Python?

Скажем, что у меня есть функция в Python, которая использует постоянное вычисленное значение float, такое как 1/3.

def div_by_3(x):
    return x * (1/3)

Если я вызову функцию повторно, будет ли значение 1/3 автоматически кэшироваться для эффективности? Или мне нужно сделать что-то вручную, например следующее:

def div_by_3(x, _ONE_THIRD=1/3):
    return x * _ONE_THIRD
4b9b3361

Ответ 1

Узнайте сами! Модуль dis отлично подходит для проверки такого рода вещей:

>>> from dis import dis
>>> def div_by_3(x):
...     return x * (1/3.)
... 
>>> dis(div_by_3)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               1 (1)
              6 LOAD_CONST               2 (3.0)
              9 BINARY_DIVIDE       
             10 BINARY_MULTIPLY     
             11 RETURN_VALUE        

Как вы можете видеть, расчет 1/3 происходит каждый раз. (Примечание: я изменил 3 на 3., чтобы заставить float-деление, иначе это будет всего лишь 0. Вы также можете включить будущее-деление, которое фактически изменило поведение, см. Раздел редактирования ниже).

И ваш второй подход:

>>> def db3(x, _ONE_THIRD=1/3.):
...   return x * _ONE_THIRD
... 
>>> dis(db3)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_FAST                1 (_ONE_THIRD)
              6 BINARY_MULTIPLY     
              7 RETURN_VALUE        

Более подробную информацию о второй можно найти inspect объекта функции:

>>> inspect.getargspec(db3)
ArgSpec(args=['x', '_ONE_THIRD'], varargs=None, keywords=None, defaults=(0.3333333333333333,))

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

EDIT. Оказывается, это немного интереснее. В Python 3 они получают кеширование (а также в Python 2.7 при включении from __future__ import division):

>>> dis.dis(div_by_3)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               3 (0.3333333333333333)
              6 BINARY_MULTIPLY
              7 RETURN_VALUE

Переключение на целочисленное деление (//) в Python 3 или 2.7-with-future-division не изменяет этого, оно просто изменяет константу как 0 вместо 0.333.. Кроме того, используя integer деление непосредственно в 2.7 без будущего разделения будет кэшировать 0.

Узнал что-то новое сегодня!