pythonstring-formatting

Print string left aligned with fixed width and suffix


Using Pythons string formatting, is there a nice way to add a suffix to a left aligned string that is padded to a fixed size?

I want to print a list of key-value-pairs in the following formatting:

a_key:        23
another_key:  42
...

The problem is the ':'. The best solution I found so far is to append the ':' to the key name:

print "{:<20}  {}".format(key+':', value)

But I think this is a rather ugly solution, as it diminishes the separation of formatting and values. Is it possible to achieve this directly in the format specification?

What I am looking for is something like this:

print "{do something here}  {}".format(key, value)

Solution

  • You cannot change "".format() as it is a built-in but if it is acceptable to provide the string and parameters to a method:

    print(kf.format("{:t{}}  {}", key, ':', value))
    

    you can do so by subclassing string.Formatter to allow empty format fields and provide a special type handler t:

    from string import Formatter
    import sys
    
    if sys.version_info < (3,):
        int_type = (int, long)
    else:
        int_type = (int)
    
    class TrailingFormatter(Formatter):
    
        def vformat(self, *args):
            self._automatic = None
            return super(TrailingFormatter, self).vformat(*args)
    
        def get_value(self, key, args, kwargs):
            if key == '':
                if self._automatic is None:
                    self._automatic = 0
                elif self._automatic == -1:
                    raise ValueError("cannot switch from manual field specification "
                                     "to automatic field numbering")
                key = self._automatic
                self._automatic += 1
            elif isinstance(key, int_type):
                if self._automatic is None:
                    self._automatic = -1
                elif self._automatic != -1:
                    raise ValueError("cannot switch from automatic field numbering "
                                     "to manual field specification")
            return super(TrailingFormatter, self).get_value(key, args, kwargs)
    
        def format_field(self, value, spec):
            if len(spec) > 1 and spec[0] == 't':
                value = str(value) + spec[1]  # append the extra character
                spec = spec[2:]
            return super(TrailingFormatter, self).format_field(value, spec)
    
    kf = TrailingFormatter()
    w = 20
    ch = ':'
    x = dict(a_key=23, another_key=42)
    
    for k in sorted(x):
        v = x[k]
        print(kf.format('{:t{}<{}} {}', k, ch, w, v))
    

    gives you:

     a_key:               23
     another_key:         42
    

    You can of course hardcode the ch, and w values:

        print(kf.format('{:t:<20} {}', k, v))
    

    for better readability, but less flexibility.


    A backport of the Python 3.4 string.Formatter() that includes a bugfix for versions (at least) up to 3.5.0rc1, that includes this code is now available on PyPI