快速检查
从函数签名中,我们可以看出它们是不同的:
pow(x, y[, z])
math.pow(x, y)
此外,在Shell中尝试一下会给您一个快速了解:
>>> pow is math.pow
False
测试差异
了解这两个函数之间行为差异的另一种方法是进行测试:
import math
import traceback
import sys
inf = float("inf")
NaN = float("nan")
vals = [inf, NaN, 0.0, 1.0, 2.2, -1.0, -0.0, -2.2, -inf, 1, 0, 2]
tests = set([])
for vala in vals:
for valb in vals:
tests.add( (vala, valb) )
tests.add( (valb, vala) )
for a,b in tests:
print("math.pow(%f,%f)"%(a,b) )
try:
print(" %f "%math.pow(a,b))
except:
traceback.print_exc()
print("__builtins__.pow(%f,%f)"%(a,b) )
try:
print(" %f "%__builtins__.pow(a,b))
except:
traceback.print_exc()
我们可以注意到一些细微的差别。例如:
math.pow(0.000000,-2.200000)
ValueError: math domain error
__builtins__.pow(0.000000,-2.200000)
ZeroDivisionError: 0.0 cannot be raised to a negative power
还有其他的区别,上面的测试列表并不完整(没有长数字,没有复杂类型等等...)但是这将给我们一个实用的列表来表明这两个函数的行为有所不同。我还建议扩展上述测试以检查每个函数返回的类型。你可以编写类似的东西,创建两个函数之间差异的报告。
math.pow()
math.pow()
与内置的 **
或 pow()
相比,处理其参数的方式非常不同。这是以灵活性为代价的。看一下 源代码,我们可以看到 math.pow()
的参数直接转换为双精度浮点数:
static PyObject *
math_pow(PyObject *self, PyObject *args)
{
PyObject *ox, *oy;
double r, x, y;
int odd_y;
if (! PyArg_UnpackTuple(args, "pow", 2, 2, &ox, &oy))
return NULL;
x = PyFloat_AsDouble(ox);
y = PyFloat_AsDouble(oy);
对于双精度浮点数,检查它们的有效性后,将结果传递给底层C数学库。
内置函数pow()
另一方面,内置的pow()
(与**
操作符相同)行为完全不同,它实际上使用了对象自己的**
操作符实现,如果需要,用户可以通过替换数字的__pow__()
、__rpow__()
或__ipow__()
方法来覆盖它。
对于内置类型,值得研究两种数字类型实现的幂函数之间的区别,例如浮点数、长整型和复数。
覆盖默认行为
模拟数字类型的方法在这里描述。如果你正在为带有不确定性的数字创建新类型,你需要为该类型提供__pow__()
、__rpow__()
和可能的__ipow__()
方法。这将允许你的数字与运算符一起使用:
class Uncertain:
def __init__(self, x, delta=0):
self.delta = delta
self.x = x
def __pow__(self, other):
return Uncertain(
self.x**other.x,
Uncertain._propagate_power(self, other)
)
@staticmethod
def _propagate_power(A, B):
return math.sqrt(
((B.x*(A.x**(B.x-1)))**2)*A.delta*A.delta +
(((A.x**B.x)*math.log(B.x))**2)*B.delta*B.delta
)
为了重写
math.pow()
,您需要进行猴子补丁以支持您的新类型:
def new_pow(a,b):
_a = Uncertain(a)
_b = Uncertain(b)
return _a ** _b
math.pow = new_pow
注意,为了使这个方法工作,你需要调整Uncertain
类以便能够处理__init__()
的输入参数是Uncertain
实例的情况。