要让它工作,你必须先规范化小数:
>>> x = decimal.Decimal ('10000000')
>>> x.normalize()
Decimal('1E+7')
>>> x.normalize().to_eng_string()
'10E+6'
可以通过深入研究源代码来发现其原因。
如果您检查 Python 2.7.3 源代码树中的 to_eng_string()(来自 gzip 压缩源 tar 球 here 的 Lib/decimal.py),它只需调用 __str__ 并将 eng 设置为 true。
然后你可以看到它决定了小数点左边有多少位最初是:
leftdigits = self._exp + len(self._int)
下表显示了这两项的值:
._exp ._int len leftdigits
----- --------- --- ----------
Decimal (1000000) 0 '1000000' 7 7
Decimal ('1E+6') 6 '1' 1 7
之后的代码是:
if self._exp <= 0 and leftdigits > -6:
# no exponent required
dotplace = leftdigits
elif not eng:
# usual scientific notation: 1 digit on left of the point
dotplace = 1
elif self._int == '0':
# engineering notation, zero
dotplace = (leftdigits + 1) % 3 - 1
else:
# engineering notation, nonzero
dotplace = (leftdigits - 1) % 3 + 1
你可以看到,除非它已经有一个在一定范围内的指数(self._exp > 0 or leftdigits <= -6),否则在字符串表示中不会给出任何指数。
进一步调查显示了这种行为的原因。查看代码本身,您会发现它基于 General Decimal Arithmetic Specification (PDF here)。
如果您在该文档中搜索 to-scientific-string(to-engineering-string 主要基于该文档),它会部分说明(转述,并带有我的粗体字):
“to-scientific-string”操作将数字转换为字符串,使用科学记数法如果需要指数。该操作不受上下文影响。
如果该数是有限数,则:
首先将系数转换为以十为底的字符串,使用字符 0 到 9,不带前导零(除非它的值为零,在这种情况下使用单个 0 字符)。
接下来,计算调整后的指数;这是指数加上转换系数中的字符数减去一。即exponent+(clength-1),其中clength为系数的十进制数字长度。
如果指数小于等于0,且调整后的指数大于等于-6,则不使用指数符号将数字转换为字符形式。在这种情况下,如果指数为零,则不添加小数点。否则(指数将为负数),将插入一个小数点,其中指数的绝对值指定小数点右侧的字符数。必要时将“0”字符添加到转换系数的左侧。如果此插入后小数点前没有字符,则以常规的“0”字符为前缀。
换句话说,它正在做它正在做的事情,因为这是标准告诉它要做的事情。