str.format和string.Formatter.format之间的区别

时间:2015-01-05 19:25:08

标签: python string format

在Python 2.7.6中,这两者都有效:

>>> '{0} {1}'.format('hello', 'world')
'hello world'
>>> '{} {}'.format('hello', 'world')
'hello world'

但其中只有一项有效:

>>> from string import Formatter
>>> Formatter().format('{0} {1}', 'hello', 'world')
'hello world'
>>> Formatter().format('{} {}', 'hello', 'world')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/string.py", line 545, in format
    return self.vformat(format_string, args, kwargs)
  File "/usr/lib/python2.7/string.py", line 549, in vformat
    result = self._vformat(format_string, args, kwargs, used_args, 2)
  File "/usr/lib/python2.7/string.py", line 571, in _vformat
    obj, arg_used = self.get_field(field_name, args, kwargs)
  File "/usr/lib/python2.7/string.py", line 632, in get_field
    obj = self.get_value(first, args, kwargs)
  File "/usr/lib/python2.7/string.py", line 591, in get_value
    return kwargs[key]
KeyError: ''

为什么str.formatstring.Formatter.format以这种方式有所不同,虽然我在文档中找不到任何暗示这一点的内容?这种差异是否意图和/或记录在哪里?

1 个答案:

答案 0 :(得分:2)

此问题/错误已raised here。它已在Python3.5中修复。


它尚未针对Python2.7进行修补。在此之前,您可以继承string.Formatter来实现自动arg索引:

import string    

class AutoArgFormatter(string.Formatter):
    """
    Backport of https://hg.python.org/cpython/rev/ad74229a6fba to Python2.7
    """
    def _vformat(self, format_string, args, kwargs, used_args, recursion_depth,
                 auto_arg_index=0):
        if recursion_depth < 0:
            raise ValueError('Max string recursion exceeded')
        result = []

        for literal_text, field_name, format_spec, conversion in \
                self.parse(format_string):

            # output the literal text
            if literal_text:
                result.append(literal_text)

            # this is some markup, find the object and do
            #  the formatting

            # handle arg indexing when empty field_names are given.
            if field_name == '':
                if auto_arg_index is False:
                    raise ValueError('cannot switch from manual field '
                                     'specification to automatic field '
                                     'numbering')
                field_name = str(auto_arg_index)
                auto_arg_index += 1
            elif field_name.isdigit():
                if auto_arg_index:
                    raise ValueError('cannot switch from manual field '
                                     'specification to automatic field '
                                     'numbering')
                # disable auto arg incrementing, if it gets
                # used later on, then an exception will be raised
                auto_arg_index = False

            # given the field_name, find the object it references
            #  and the argument it came from
            obj, arg_used = self.get_field(field_name, args, kwargs)
            used_args.add(arg_used)

            # do any conversion on the resulting object
            obj = self.convert_field(obj, conversion)

            # expand the format spec, if needed
            format_spec = self._vformat(format_spec, args, kwargs,
                                        used_args, recursion_depth-1,
                                        auto_arg_index=auto_arg_index)

            # format the object and append to the result
            result.append(self.format_field(obj, format_spec))

        return ''.join(result)

fmt = AutoArgFormatter()
print(fmt.format('{} {}', 'hello', 'world'))

产量

hello world