在字符串中将截断的Python浮点数格式化为整数

51

一个简单易懂的决策:

some_float = 1234.5678
print '%02d' % some_float  # 1234

some_float = 1234.5678
print '{WHAT?}'.format(some_float) # I want 1234 here too

注:选项{:.0f}不可行,因为它会四舍五入(在此示例中返回1235)。

format(..., int(some_float))正是我想要避免的,请不要建议使用它。


3
也许是因为它四舍五入而不是截断?"{:.0f}".format(1234.5678)的结果是"1235"而不是"1234" - Blckknght
1
如果将浮点数转换为 int() 或截断它是唯一的选项怎么办?下一步是创建一个自定义的 float() 子类来自定义 .__format__() 钩子。 - Martijn Pieters
请注意,在此代码片段中:'%02d' % some_float,隐式转换为 int 正在发生,你无法避免某种形式的转换以打印所需的格式。 - Óscar López
2
你为什么要排除正确的解决方案? - Stefano Palazzo
1
我很好奇为什么您要避免 int(some_float),但您接受的答案是一个既复杂又绕弯子的解决方法,而它实际上就是这样做的。前者似乎更容易理解和维护。 - Andrew Cottrell
2
@AndrewCottrell:现在已经快5年了,所以很难说当时我为什么想要那个东西;可能是为了让{some_var:d}能够正常工作而不需要额外的转换。 - georg
4个回答

35

值得一提的是,使用原始格式字符串渲染浮点数时的内置行为。如果您事先知道小数部分相对于0.5的位置,则可以利用最初尝试但因四舍五入效应而未能实现的格式字符串"{:0.0f}"。请查看以下示例...

>>> "{:0.0f}".format(1.999)
'2'
>>> "{:0.0f}".format(1.53)
'2'
>>> "{:0.0f}".format(1.500)
'2'
>>> "{:0.0f}".format(1.33)
'1'
>>> "{:0.0f}".format(0.501)
'1'
>>> "{:0.0f}".format(0.5)
'0'
>>> "{:0.0f}".format(0.1)
'0'
>>> "{:0.0f}".format(0.001)
'0'

正如您所看到的,背后有舍入行为。在我的情况下,我知道我要处理的是一个非分数部分,只想将浮点数的整数部分呈现在html模板中作为解决方法。当然,如果您不事先知道小数部分,则需要首先对浮点数执行截断操作。


21

通过扩展类string.Formatter,可以扩展标准字符串格式化语言:

class MyFormatter(Formatter):
    def format_field(self, value, format_spec):
        if format_spec == 't':  # Truncate and render as int
            return str(int(value))
        return super(MyFormatter, self).format_field(value, format_spec)

MyFormatter().format("{0} {1:t}", "Hello", 4.567)  # returns "Hello 4"

17

这个有效:

from math import trunc
some_float = 1234.5678

print '{:d}'.format(trunc(some_float))
=> 1234

或者就这样做,说到这个问题:

print trunc(some_float)
=> 1234

我认为这是一个可以接受的答案,它避免了转换为int。请注意,在此代码片段中:'%02d' % some_float发生了隐式转换为int,你无法避免某种形式的转换以按所需格式打印。


-7

这也可以工作:

some_float = 1234.5678
f = lambda x: str(x)[:str(x).find('.')]
print '{}'.format(f(some_float))
=> 1234

经过进行%timeit测试,看起来这比截断方法要快一些。


7
呃。。。那真是个糟糕的技术。 - Vlad
@Vlad,你能解释一下为什么吗?是因为这个函数涉及到多个步骤,所以应该将步骤分开以使其更易读,还是有其他原因?我想了解为什么这样做不好,以便我可以改进。谢谢。 - John Volk
@JohnVolk 对于它所做的事情来说,这是不必要的hacky方法,你将浮点数转换为字符串作为中间步骤来将其转换为整数 - 为什么不例如使用模运算符来获取除以1的余数,并从浮点数中减去它(即使您必须剥离2个最后字符以删除.0)?当然,与其他答案中提出的解决方案相比,这仍然是一个糟糕的解决方案。 - Markus von Broady
@MarkusvonBroady 好的,感谢反馈。我刚刚对此进行了一个 %%timeit 测试,我的答案确实比使用 math.trunc 的被接受答案要快一些。而且,它不会将数字转换为字符串再转回整数,它只是将其强制转换为字符串并返回找到但不包括小数点字符的内容。如果你想要更易读的东西,可以将其分成两行,x = str(x) 和 x[:x.find('.')]。 - John Volk
3
快速的解决方案通常不会被严重批评,但在大多数情况下,小幅性能提升并不值得采用"hacky"方法(而且不符合Python惯用法,外观也不好看)。但我没有给你投反对票。 - Markus von Broady

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接