Ответ 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
.
Узнал что-то новое сегодня!