python字符串格式:何时使用!s转换标志

Python string format: When to use !s conversion flag

这两个字符串格式语句在python中的区别是什么:

1
2
'{0}'.format(a)
'{0!s}'.format(a)

如果a是整数、列表或字典,则两者的输出相同。第一个{0}是否执行隐式str()调用?

来源

附言:关键词:感叹/砰"!S格式


文件中提到:

The conversion field causes a type coercion before formatting.
Normally, the job of formatting a value is done by the __format__()
method of the value itself. However, in some cases it is desirable to
force a type to be formatted as a string, overriding its own
definition of formatting. By converting the value to a string before
calling __format__(), the normal formatting logic is bypassed.

Two conversion flags are currently supported: '!s' which calls
str() on the value, and '!r' which calls repr().

可以(再次从文档中)举一个例子来说明区别:

1
2
>>>"repr() shows quotes: {!r}; str() doesn't: {!s}".format('test1', 'test2')
"repr() shows quotes: 'test1'; str() doesn't: test2"


简单地说:

  • '{0}'.format(a)将使用a.__format__()的结果显示该值。
  • '{0!s}'.format(a)将使用a.__str__()的结果显示该值。
  • '{0!r}'.format(a)将使用a.__repr__()的结果显示该值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> class C:
...     def __str__(self): return"str"
...     def __repr__(self): return"repr"
...     def __format__(self, format_spec): return"format as" + str(type(format_spec))
...
>>> c = C()
>>> print"{0}".format(c)
format as <type 'str'>
>>> print u"{0}".format(c)
format as <type 'unicode'>
>>> print"{0!s}".format(c)
str
>>> print"{0!r}".format(c)
repr

关于__format__的第二个参数,引用pep 3101"按类型控制格式":

The 'format_spec' argument will be either
a string object or a unicode object, depending on the type of the
original format string. The __format__ method should test the type
of the specifiers parameter to determine whether to return a string or
unicode object. It is the responsibility of the __format__ method
to return an object of the proper type.


感谢@hjpotter92的评论和回答,请解释:

下面是一个显示差异的示例(当您重写__format__方法时)

1
2
3
4
5
6
7
8
9
10
11
12
class MyClass:
    i = 12345
    def __format__(self, i):
        return 'I Override'

>>> obj = MyClass()

>>> '{0}'.format(obj)
'I Override'

>>> '{0!s}'.format(obj)
'<__main__.MyClass instance at 0x021AA6C0>'