Использование оператора электропитания **
будет быстрее, так как оно не будет иметь накладных расходов на вызов функции. Вы можете увидеть это, если вы разобрать код Python:
>>> dis.dis('7. ** i')
1 0 LOAD_CONST 0 (7.0)
3 LOAD_NAME 0 (i)
6 BINARY_POWER
7 RETURN_VALUE
>>> dis.dis('pow(7., i)')
1 0 LOAD_NAME 0 (pow)
3 LOAD_CONST 0 (7.0)
6 LOAD_NAME 1 (i)
9 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
12 RETURN_VALUE
>>> dis.dis('math.pow(7, i)')
1 0 LOAD_NAME 0 (math)
3 LOAD_ATTR 1 (pow)
6 LOAD_CONST 0 (7)
9 LOAD_NAME 2 (i)
12 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
15 RETURN_VALUE
Обратите внимание, что я использую переменную i
в качестве показателя здесь, потому что постоянные выражения, как 7. ** 5
фактически оцениваются во время компиляции.
Теперь, на практике эта разница не имеет значения, что многое, как вы можете видеть, когда это время:
>>> from timeit import timeit
>>> timeit('7. ** i', setup='i = 5')
0.2894785532627111
>>> timeit('pow(7., i)', setup='i = 5')
0.41218495570683444
>>> timeit('math.pow(7, i)', setup='import math; i = 5')
0.5655053168791255
Таким образом, в то время как pow
и math.pow
примерно в два раза медленнее, они все еще достаточно быстро, чтобы не волнует много. Если вы не сможете на самом деле идентифицировать возведение в степень как узкое место, не будет причины выбирать один метод над другим, если ясность уменьшается. Это особенно актуально, поскольку pow
предлагает интегрированную модульную операцию, например.
Альфей задал хороший вопрос в комментариях выше:
timeit
показывает, что math.pow
медленнее, чем **
во всех случаях. Что такое math.pow()
хорошо в любом случае? Есть ли у кого-нибудь идея, где это может быть какое-то преимущество тогда?
Большая разница math.pow
как с встроено pow
и оператор питания **
является то, что он всегда использует всплывают семантику. Поэтому, если вы по какой-то причине хотите убедиться, что вы вернете поплавок, то math.pow
обеспечит это свойство.
Давайте рассмотрим пример: у нас есть два номера, i
и j
, и понятия не имею, являются ли они поплавками или целыми числами. Но мы хотим получить результат поплавка i^j
. Итак, какие у нас варианты?
- Мы можем преобразовать хотя бы один из аргументов в поплавок, а затем сделать
i ** j
.
- Мы можем сделать и преобразовать результат в поплавок (показатель экспоненциальности float автоматически используется, когда
i
или j
являются поплавками, поэтому результат тот же).
- Мы можем использовать
math.pow
.
Итак, давайте проверить это:
>>> timeit('float(i) ** j', setup='i, j = 7, 5')
0.7610865891750791
>>> timeit('i ** float(j)', setup='i, j = 7, 5')
0.7930400942188385
>>> timeit('float(i ** j)', setup='i, j = 7, 5')
0.8946636625872202
>>> timeit('math.pow(i, j)', setup='import math; i, j = 7, 5')
0.5699394063529439
Как вы можете видеть, math.pow
на самом деле быстрее! И если вы подумаете об этом, накладные расходы от вызова функции также исчезли, потому что во всех остальных альтернативах мы должны позвонить float()
.
Кроме того, может быть, стоит отметить, что поведение **
и pow
может быть перекрыто путем реализации методы специального __pow__
(и __rpow__
) для пользовательских типов. Поэтому, если вы этого не хотите (по какой-либо причине), использование math.pow
этого не сделает.
Почему бы не 'timeit' узнать? – mgilson
'timeit' показывает, что' math.pow' медленнее, чем '**' во всех случаях. Что такое 'math.pow()' хорошо в любом случае? Есть ли у кого-нибудь идея, где это может быть какое-то преимущество тогда? – Alfe
Это вряд ли имеет значение. Ваш код будет узким местом, а не этими функциями. – duffymo