54

A quick no-brainer:

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

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

Note: {:.0f} is not an option, because it rounds (returns 1235 in this example).

format(..., int(some_float)) is exactly the thing I'm trying to avoid, please don't suggest that.

6
  • 3
    @MartijnPieters Perhaps because it rounds rather than truncates? "{:.0f}".format(1234.5678) is "1235", not "1234". Commented Nov 22, 2012 at 11:26
  • 1
    What if converting the float to int() or truncating it are the only options? Next step is to create a custom float() subclass to customize the .__format__() hook. Commented Nov 22, 2012 at 11:31
  • 2
    Why are you excluding the correct solution? Commented Mar 23, 2017 at 10:23
  • 1
    I'm curious why int(some_float) is what you're trying to avoid, yet your accepted answer is a convoluted workaround that does that exact thing. The former seems much easier to understand and maintain. Commented Jun 2, 2017 at 16:58
  • 2
    @AndrewCottrell: it's almost 5 years from now, so it's hard to say why I wanted that back then ;) Probably to make {some_var:d} work without extra conversions. Commented Jun 2, 2017 at 19:26

4 Answers 4

40

It's worth mentioning the built in behavior for how floats are rendered using the raw format strings. If you know in advance where your fractional part lies with respect to 0.5 you can leverage the format string you originally attempted but discovered it fell short from rounding side effects "{:0.0f}". Check out the following examples...

>>> "{: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'

As you can see there's rounding behavior behind the scenes. In my case where I had a database converting ints to floats I knew I was dealing with a non fractional part in advance and only wanted to render in an html template the int portion of the float as a workaround. Of course if you don't know in advance the fractional part you would need to carry out a truncation operation of some sort first on the float.

Sign up to request clarification or add additional context in comments.

Comments

22

It's possible to extend the standard string formatting language by extending the class 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"

Comments

17

This works:

from math import trunc
some_float = 1234.5678

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

Or just do this, for that matter:

print trunc(some_float)
=> 1234

I think it's an acceptable answer, it avoids the conversion to int. Notice that in this snippet: '%02d' % some_float an implicit conversion to int is happening, you can't avoid some sort of conversion for printing in the desired format.

Comments

-7

This will work too:

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

After doing a %timeit test it looks like this is a bit faster than the trunc method.

5 Comments

Ugh.. that's really bad technique
@Vlad can you explain why? Should the steps be separated out to be more readable or is it just because the function involves several steps? I would like to learn why it is bad so that I can improve, thanks.
@JohnVolk It's unnecessarily hacky for what it does, you're converting a float to a string as an intermediate step to convert it to an integer - why not for example use a modulo operator to get the reminder from division by 1, and subtract that from the float number (even if you had to strip 2 last characters then in order to remove .0)? Of course that would still be a bad solution compared to those presented in other answers.
@MarkusvonBroady OK thanks for the feedback. I just did a %%timeit test on this and sure enough my answer is a bit faster than the accepted answer which uses math.trunc. Also, it does not convert to a string and back to an int, it just casts to a string and returns what is found up to but not inclusive of the period character. If you want something more readable break it into two lines, x = str(x) and x[:x.find('.')].
@JohnVolk a solution that is fast is surely good enough not to be downvoted to smithereens, but in most cases that little performance gain is not worth the potential troubles of the hacky way (as well as poor aesthetic of not being python idiomatic). But I didn't downvote you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.