string formatting specifications

Gribouillis Gribouillis is offline Offline Oct 22nd, 2009, 2:32 pm |
2
The syntax of the str.format() method described in the python 2.6 documentation looks both powerful and complex. The idea of this thread is to start a collection of nice formatting examples which will ease the task of mastering this function. Please post useful examples, and document them
Quick reply to this message  
Python Syntax
  1. rabbits = {
  2. "flopsy" : 1.0/3,
  3. "mopsy" : 576.0/7,
  4. "cotton tail": .76/5,
  5. "peter": 300000.0/37,
  6. }
  7.  
  8. for name in sorted(rabbits):
  9. # 13 and 10 are field width, > means right align,
  10. # .4f means a float with 4 digits after '.'
  11. print("{name:13}:{score:>10.4f}".format(name=name, score=rabbits[name]))
  12.  
  13. """my output ---->
  14. cotton tail : 0.1520
  15. flopsy : 0.3333
  16. mopsy : 82.2857
  17. peter : 8108.1081
  18. """
1
Gribouillis Gribouillis is offline Offline | Oct 22nd, 2009
Same example with computed field's width:
  1. rabbits = {
  2. "flopsy" : 1.0/3, "mopsy" : 576.0/7, "cotton tail": .76/5, "peter": 300000.0/37,
  3. }
  4.  
  5. nwidth = 1 + max(len(name) for name in rabbits)
  6.  
  7. for name in sorted(rabbits):
  8. # the name field's width is passed as argument to format
  9. print("{name:{namewidth}}:{score:>10.4f}".format(
  10. name = name, score = rabbits[name], namewidth = nwidth))
  11.  
  12. """my output ---->
  13. cotton tail : 0.1520
  14. flopsy : 0.3333
  15. mopsy : 82.2857
  16. peter : 8108.1081
  17. """
Last edited by Gribouillis; Oct 22nd, 2009 at 4:06 pm.
 
1
Gribouillis Gribouillis is offline Offline | Oct 22nd, 2009
The floating point precision can be passed as argument too
  1. rabbits = {
  2. "flopsy" : 1.0/3, "mopsy" : 576.0/7, "cotton tail": .76/5, "peter": 300000.0/37,
  3. }
  4.  
  5. nwidth = 1 + max(len(name) for name in rabbits)
  6.  
  7. for name in sorted(rabbits):
  8. # the floating point precision is passed as argument to format
  9. print("{name:{namewidth}}:{score:>10.{precision}f}".format(
  10. name = name, score = rabbits[name],
  11. namewidth = nwidth, precision = 2))
  12.  
  13. """my output ---->
  14. cotton tail : 0.15
  15. flopsy : 0.33
  16. mopsy : 82.29
  17. peter : 8108.11
  18. """
Last edited by Gribouillis; Oct 22nd, 2009 at 4:01 pm.
 
0
Gribouillis Gribouillis is offline Offline | Oct 22nd, 2009
White space in the fields can be filled with a single character.
  1. rabbits = {
  2. "flopsy" : 1.0/3, "mopsy" : 576.0/7, "cotton tail": .76/5, "peter": 300000.0/37,
  3. }
  4.  
  5. nwidth = 1 + max(len(name) for name in rabbits)
  6.  
  7. for name in sorted(rabbits):
  8. # A single character can be used before the alignment sign (< ^ = or >)
  9. # to fill white space in each field.
  10. print("{name:{fill}<{namewidth}}{score:{fill}>20.{precision}f}".format(
  11. name = name, score = rabbits[name],
  12. namewidth = nwidth, precision = 2, fill="-"))
  13.  
  14. """my output ---->
  15. cotton tail-----------------0.15
  16. flopsy----------------------0.33
  17. mopsy----------------------82.29
  18. peter--------------------8108.11
  19. """
Last edited by Gribouillis; Oct 22nd, 2009 at 4:52 pm.
 
0
Gribouillis Gribouillis is offline Offline | Oct 22nd, 2009
For complex templates, we can use functools.partial to set the value of some of the template's arguments. This results in a cleaner code
  1. import functools
  2. rabbits = {
  3. "flopsy" : 1.0/3, "mopsy" : 576.0/7, "cotton tail": .76/5, "peter": 300000.0/37,
  4. }
  5.  
  6. template = "{name:{fill}<{namewidth}}{score:{fill}>20.{precision}f}"
  7.  
  8. nwidth = 1 + max(len(name) for name in rabbits)
  9. # The use of functools.partial allows us to give a value to a subset of
  10. # the template's arguments.
  11. rabbit_line = functools.partial(template.format,
  12. namewidth = nwidth, precision = 2, fill="-")
  13.  
  14. for name in sorted(rabbits):
  15. print(rabbit_line(name = name, score = rabbits[name]))
  16.  
  17. """my output ---->
  18. cotton tail-----------------0.15
  19. flopsy----------------------0.33
  20. mopsy----------------------82.29
  21. peter--------------------8108.11
  22. """
Last edited by Gribouillis; Oct 22nd, 2009 at 6:00 pm.
 
1
vegaseat vegaseat is offline Offline | Oct 22nd, 2009
Access a dictionary directly ...
  1. # a food:price dictionary
  2. food_dict = {
  3. 'soymilk' : 3.69,
  4. 'butter' : 1.95,
  5. 'bread' : 2.19,
  6. 'cheese' : 4.39
  7. }
  8.  
  9. # pull one key item like 'bread' out of the dictionary
  10. print("Bread = ${bread:4.2f}".format(**food_dict)) # Bread = $2.19
 
0
Gribouillis Gribouillis is offline Offline | Oct 22nd, 2009
Formatting specifications for datetime.datetime objects differ from the standard ones. They obey the rules of datetime.datetime.strftime. Each class can define its own formatting specifications through its __format__ method.
  1. from datetime import datetime
  2. import sys
  3. from os.path import getmtime
  4.  
  5. python = sys.executable
  6. pytime = datetime.fromtimestamp(getmtime(python))
  7.  
  8. print("My python executable was last modified on {t:%b %d %Y} at {t:%H:%M:%S}."
  9. .format(t=pytime))
  10.  
  11. """my output ---->
  12. My python executable was last modified on Aug 22 2009 at 18:38:31.
  13. """
Last edited by Gribouillis; Oct 22nd, 2009 at 9:16 pm.
 
0
Gribouillis Gribouillis is offline Offline | Oct 23rd, 2009
The different floating point formatting types (exponential, fixed, general, number and percentage).
  1. from math import pi
  2.  
  3. ftypes = "e E f F g G n %".split()
  4.  
  5. header = "".join("{{types[{i}]:^10}}".format(i = i) for i in range(len(ftypes)))
  6. line = "".join("{{val:^10.2{tp}}}".format(tp = t) for t in ftypes)
  7.  
  8. print(line)
  9. print('')
  10. print(header.format(types = ftypes))
  11. print("-" * 80)
  12. for x in (pi*pi, 1.0/pi, pi **(-9), pi**17):
  13. print(line.format(val = x))
  14.  
  15. """ my output ---->
  16. {val:^10.2e}{val:^10.2E}{val:^10.2f}{val:^10.2F}{val:^10.2g}{val:^10.2G}{val:^10.2n}{val:^10.2%}
  17.  
  18. e E f F g G n %
  19. --------------------------------------------------------------------------------
  20. 9.87e+00 9.87E+00 9.87 9.87 9.9 9.9 9.9 986.96%
  21. 3.18e-01 3.18E-01 0.32 0.32 0.32 0.32 0.32 31.83%
  22. 3.35e-05 3.35E-05 0.00 0.00 3.4e-05 3.4E-05 3.4e-05 0.00%
  23. 2.83e+08 2.83E+08 282844563.59282844563.59 2.8e+08 2.8E+08 2.8e+08 28284456358.65%
  24. """
Note that for large numbers, the exponential notation is superior. Also note that for the g and G type, the precision .2 is interpreted as a number of significant digits.
Last edited by Gribouillis; Oct 23rd, 2009 at 4:13 am.
 
0
Gribouillis Gribouillis is offline Offline | Oct 23rd, 2009
For non numeric types, the precision is interpreted as a maximum field's width (the normal field's width is a minimum width).
  1. class Animal():
  2. def __init__(self, name):
  3. self.name = name
  4. def __repr__(self):
  5. return "Animal({0})".format(self.name)
  6.  
  7. animals = [ Animal(name) for name in "python lion giraffe antelope gnu".split() ]
  8.  
  9. # Each field has a minimum width (10) and a maximum width (13).
  10. # The field's content is truncated if necessary.
  11. # this works only for non numeric fields.
  12. template = " | ".join("{{seq[{index}]:10.13}}".format(index = i) for i in range(len(animals)))
  13.  
  14.  
  15. print("template: " + template)
  16. print(template.format(seq = animals))
  17.  
  18. """ my output ---->
  19. template: {seq[0]:10.13} | {seq[1]:10.13} | {seq[2]:10.13} | {seq[3]:10.13} | {seq[4]:10.13}
  20. result:
  21. Animal(python | Animal(lion) | Animal(giraff | Animal(antelo | Animal(gnu)
  22. """
Last edited by Gribouillis; Oct 23rd, 2009 at 5:14 am.
 
0
Gribouillis Gribouillis is offline Offline | Oct 23rd, 2009
Adding alignment and field widths capabilities. Since objects like datetime.datetime have their custom formatting syntax, they don't support alignment and field width capabilities.
For example, formatting a datetime with {time:>20%H:%M:%S} won't cause the time to be right aligned in a field of length 20. Instead, the string >20 will be printed verbatim.
Using the __format__ method, it's easy to write a general wrapper class Align which gives other objects the ability to handle alignment and field width in formatting operations.
  1. #!/usr/bin/env python
  2. from functools import update_wrapper
  3. import re
  4. _align_re =re .compile (r"^([<^>]?[0-9]*)(?:[.][0-9]*)?")
  5.  
  6. def with_align (format_method ,maxwidth =True ):
  7. """Decorator for custom __format__ methods.
  8. Gives a __format__ method the ability to handle
  9. alignment character and field min width and max width
  10. with the syntax [align][minwidth].[maxwidth]
  11. similar to the standard formatting syntax
  12. """
  13. def wrapper (self ,format_spec ):
  14. match =_align_re .match (format_spec )
  15. index =match .end (0 if maxwidth else 1 )
  16. match ,format_spec =format_spec [:index ],format_spec [index :]
  17. data_str =format_method (self ,format_spec )
  18. if match :
  19. data_str =("{0:"+match +"}").format (data_str )
  20. return data_str
  21. update_wrapper (wrapper ,format_method )
  22. return wrapper
  23.  
  24. class Align (object ):
  25. """Wrapper class to allow format alignment.
  26. Wrapping an object in Align adds alignment capabilities
  27. to the object in formatting operations.
  28. Example: "Time is {0:>10%H%M%S}".format(Align(datetime.now()))
  29. """
  30. def __init__ (self ,wrapped_obj ):
  31. self .wrapped_obj =wrapped_obj
  32.  
  33. @with_align
  34. def __format__ (self ,format_spec ):
  35. return ("{0:"+format_spec +"}").format (self .wrapped_obj )
  36.  
  37. def dtime ():
  38. "Returns a datetime object for testing purposes"
  39. from sys import executable as python
  40. from datetime import datetime
  41. from os .path import getmtime
  42. return datetime .fromtimestamp (getmtime (python ))
  43.  
  44. def atest ():
  45. "Test of formatting a datetime object with alignment"
  46. print ("Test without Align:")
  47. # The alignment and field width can't be used for datetime
  48. print ("Time was: {time:>20%H:%M:%S}".format (time =dtime ()))
  49. # Wrapping the datetime object in an Align object allows
  50. # to handle the alignment specification
  51. print ("Test with Align:")
  52. print ("Time was: {time:>20%H:%M:%S}".format (time =Align (dtime ())))
  53.  
  54. atest ()
  55. """ my output ---->
  56. Test without Align:
  57. Time was: >2018:38:31
  58. Test with Align:
  59. Time was: 18:38:31 # correctly aligned
  60. """
The Align wrapper can be used for other kind of objects, and the decorator can be used to give the desired properties to user defined classes without the need to wrap the object in an Align wrapper.
Last edited by Gribouillis; Oct 23rd, 2009 at 4:52 pm.
 
 

Tags
format, string

Message:


Thread Tools Search this Thread



About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC