这里发生了一些不同的事情。
首先,Python 有两种将对象转换为字符串的机制,称为repr
和str
。 repr
应该提供“忠实”的输出,(理想情况下)可以很容易地准确地重新创建该对象,同时str
旨在获得更多人类可读的输出。对于 Python 3.1 及以下版本中repr
的浮点数,提供足够的数字来完全确定浮点数的值(以便评估返回的字符串会准确地返回该浮点数),同时str
四舍五入到小数点后 12 位;这具有隐藏不准确性的效果,但意味着非常接近的两个不同的浮点数最终可能具有相同的str
值 - 这是 . 不会发生的事情repr
。当你打印一个对象时,你会得到str
那个物体的。相反,当您只是在解释器提示符处计算表达式时,您会得到repr
.
例如(这里使用 Python 2.7):
>>> x = 1.0 / 7.0
>>> str(x)
'0.142857142857'
>>> repr(x)
'0.14285714285714285'
>>> print x # print uses 'str'
0.142857142857
>>> x # the interpreter read-eval-print loop uses 'repr'
0.14285714285714285
但是,从您的角度来看,有点令人困惑,我们得到:
>>> x = 0.4
>>> str(x)
'0.4'
>>> repr(x)
'0.4'
这似乎与您在上面看到的内容不太吻合,但我们将在下面回到这一点。
要记住的第二件事是,在您的第一个示例中,您正在打印两个单独的项目,而在您的第二个示例(已j
删除)中,您正在打印一个项目:长度为 2 的元组。有点令人惊讶的是,当用 转换一个元组以打印时str
,Python 仍然使用repr
来计算该元组元素的字符串表示:
>>> x = 1.0 / 7.0
>>> print x, x # print x twice; uses str(x)
0.142857142857 0.142857142857
>>> print(x, x) # print a single tuple; uses repr(x)
(0.14285714285714285, 0.14285714285714285)
这就解释了为什么在这两种情况下你会看到不同的结果,即使底层的浮点数是相同的。
但还有最后一块拼图。在 Python >= 2.7 中,我们在上面看到对于特定的 float 0.4
,该float 的str
andrepr
是相同的。那么0.40000000000000002
从哪里来呢?好吧,这里没有 Python 浮点数:因为您从 NumPy 数组中获取这些值,它们实际上是 type numpy.float64
:
>>> from numpy import zeros
>>> A = zeros((2, 2))
>>> A[:] = [[0.6, 0.4], [0.4, 0.6]]
>>> A
array([[ 0.6, 0.4],
[ 0.4, 0.6]])
>>> type(A[0, 0])
<type 'numpy.float64'>
该类型仍然存储一个双精度浮点数,就像 Python 的浮点数一样,但它有一些额外的好处,使其能够与 NumPy 的其余部分很好地交互。事实证明,NumPy 计算a 的算法与 Python计算repr
a 的算法略有不同。Python(在 >= 2.7 版本中)旨在提供仍然准确表示浮点数的最短字符串,而 NumPy 仅根据将基础值四舍五入为 17 位有效数字来输出字符串。回到上面那个例子,下面是 NumPy 的作用:numpy.float64
repr
float
0.4
>>> from numpy import float64
>>> x = float64(1.0 / 7.0)
>>> str(x)
'0.142857142857'
>>> repr(x)
'0.14285714285714285'
>>> x = float64(0.4)
>>> str(x)
'0.4'
>>> repr(x)
'0.40000000000000002'
所以这三件事一起应该解释你所看到的结果。请放心,这完全是装饰性的:底层浮点值不会以任何方式改变;它只是被两种类型的str
和的四种不同可能组合以不同的方式显示:和.repr
float
numpy.float64
Python 教程提供了有关Python 浮点数如何存储和显示的更多详细信息,以及一些潜在的陷阱。这个 SO question的答案有更多关于str
和之间区别的信息repr
。