有多种字符串格式设置方法:

Python<2.6:“您好%s”%namePython 2.6+:“Hello{}”.format(name)(使用str.format)Python 3.6+:f“{name}”(使用f-string)

哪种情况更好?在什么情况下?


以下方法具有相同的结果,那么有什么区别?name=“爱丽丝”“你好%s”%name“您好{0}”.format(名称)f“您好{name}”#使用命名参数:“您好%(kwarg)s”%{'kwarg':name}“你好{kwarg}”.format(kwarg=name)f“您好{name}”字符串格式化何时运行,如何避免运行时性能损失?


如果您试图结束一个重复的问题,该问题只是在寻找一种格式化字符串的方法,请使用How do I put a variable value in a string?。


当前回答

%比我测试的格式性能更好。

测试代码:

Python 2.7.2:

import timeit
print 'format:', timeit.timeit("'{}{}{}'.format(1, 1.23, 'hello')")
print '%:', timeit.timeit("'%s%s%s' % (1, 1.23, 'hello')")

结果:

> format: 0.470329046249
> %: 0.357107877731

Python 3.5.2

import timeit
print('format:', timeit.timeit("'{}{}{}'.format(1, 1.23, 'hello')"))
print('%:', timeit.timeit("'%s%s%s' % (1, 1.23, 'hello')"))

后果

> format: 0.5864730989560485
> %: 0.013593495357781649

在Python2中,差异很小,而在Python3中,%比格式快得多。

感谢@Chris Cogdon提供的示例代码。

编辑1:

2019年7月在Python 3.7.2中再次测试。

结果:

> format: 0.86600608
> %: 0.630180146

没有太大区别。我想Python正在逐步改进。

编辑2:

在有人在评论中提到python 3的f-string之后,我在python 3.7.2下测试了以下代码:

import timeit
print('format:', timeit.timeit("'{}{}{}'.format(1, 1.23, 'hello')"))
print('%:', timeit.timeit("'%s%s%s' % (1, 1.23, 'hello')"))
print('f-string:', timeit.timeit("f'{1}{1.23}{\"hello\"}'"))

结果:

format: 0.8331376779999999
%: 0.6314778750000001
f-string: 0.766649943

似乎f-string仍然比%慢,但比格式好。

其他回答

顺便说一句,在日志记录中使用新样式的格式并不一定会影响性能。您可以将任何对象传递给实现__str__魔术方法的logging.debug、logging.info等。当日志模块决定必须发出消息对象(无论是什么)时,它会在发出消息之前调用str(message_object)

import logging


class NewStyleLogMessage(object):
    def __init__(self, message, *args, **kwargs):
        self.message = message
        self.args = args
        self.kwargs = kwargs

    def __str__(self):
        args = (i() if callable(i) else i for i in self.args)
        kwargs = dict((k, v() if callable(v) else v) for k, v in self.kwargs.items())

        return self.message.format(*args, **kwargs)

N = NewStyleLogMessage

# Neither one of these messages are formatted (or calculated) until they're
# needed

# Emits "Lazily formatted log entry: 123 foo" in log
logging.debug(N('Lazily formatted log entry: {0} {keyword}', 123, keyword='foo'))


def expensive_func():
    # Do something that takes a long time...
    return 'foo'

# Emits "Expensive log entry: foo" in log
logging.debug(N('Expensive log entry: {keyword}', keyword=expensive_func))

Python 3文档中对此进行了描述(https://docs.python.org/3/howto/logging-cookbook.html#formatting-样式)。但是,它也可以与Python 2.6一起使用(https://docs.python.org/2.6/library/logging.html#using-作为消息的任意对象)。

使用此技术的一个优点是,它允许延迟值,例如上面的函数expensive_func,而不是格式化样式不可知。这为Python文档中给出的建议提供了一个更优雅的替代方案:https://docs.python.org/2.6/library/logging.html#optimization.

模运算符(%)无法执行的操作,afaik:

tu = (12,45,22222,103,6)
print '{0} {2} {1} {2} {3} {2} {4} {2}'.format(*tu)

后果

12 22222 45 22222 103 22222 6 22222

非常有用。

另一点:format()是一个函数,可以用作其他函数中的参数:

li = [12,45,78,784,2,69,1254,4785,984]
print map('the number is {}'.format,li)   

print

from datetime import datetime,timedelta

once_upon_a_time = datetime(2010, 7, 1, 12, 0, 0)
delta = timedelta(days=13, hours=8,  minutes=20)

gen =(once_upon_a_time +x*delta for x in xrange(20))

print '\n'.join(map('{:%Y-%m-%d %H:%M:%S}'.format, gen))

结果如下:

['the number is 12', 'the number is 45', 'the number is 78', 'the number is 784', 'the number is 2', 'the number is 69', 'the number is 1254', 'the number is 4785', 'the number is 984']

2010-07-01 12:00:00
2010-07-14 20:20:00
2010-07-28 04:40:00
2010-08-10 13:00:00
2010-08-23 21:20:00
2010-09-06 05:40:00
2010-09-19 14:00:00
2010-10-02 22:20:00
2010-10-16 06:40:00
2010-10-29 15:00:00
2010-11-11 23:20:00
2010-11-25 07:40:00
2010-12-08 16:00:00
2010-12-22 00:20:00
2011-01-04 08:40:00
2011-01-17 17:00:00
2011-01-31 01:20:00
2011-02-13 09:40:00
2011-02-26 18:00:00
2011-03-12 02:20:00

正如我今天发现的,通过%格式化字符串的旧方法不支持Decimal,这是Python的十进制定点和浮点运算模块,开箱即用。

示例(使用Python 3.3.5):

#!/usr/bin/env python3

from decimal import *

getcontext().prec = 50
d = Decimal('3.12375239e-24') # no magic number, I rather produced it by banging my head on my keyboard

print('%.50f' % d)
print('{0:.50f}'.format(d))

输出:

0.000000000000000000000003123752390000000099074648500.00000000000000000000000312375239000000000000000000

当然可能会有变通办法,但您仍然可以考虑立即使用format()方法。

format还有另一个优点(我在答案中没有看到):它可以获取对象财产。

In [12]: class A(object):
   ....:     def __init__(self, x, y):
   ....:         self.x = x
   ....:         self.y = y
   ....:         

In [13]: a = A(2,3)

In [14]: 'x is {0.x}, y is {0.y}'.format(a)
Out[14]: 'x is 2, y is 3'

或者,作为关键字参数:

In [15]: 'x is {a.x}, y is {a.y}'.format(a=a)
Out[15]: 'x is 2, y is 3'

据我所知,%是不可能的。

%比我测试的格式性能更好。

测试代码:

Python 2.7.2:

import timeit
print 'format:', timeit.timeit("'{}{}{}'.format(1, 1.23, 'hello')")
print '%:', timeit.timeit("'%s%s%s' % (1, 1.23, 'hello')")

结果:

> format: 0.470329046249
> %: 0.357107877731

Python 3.5.2

import timeit
print('format:', timeit.timeit("'{}{}{}'.format(1, 1.23, 'hello')"))
print('%:', timeit.timeit("'%s%s%s' % (1, 1.23, 'hello')"))

后果

> format: 0.5864730989560485
> %: 0.013593495357781649

在Python2中,差异很小,而在Python3中,%比格式快得多。

感谢@Chris Cogdon提供的示例代码。

编辑1:

2019年7月在Python 3.7.2中再次测试。

结果:

> format: 0.86600608
> %: 0.630180146

没有太大区别。我想Python正在逐步改进。

编辑2:

在有人在评论中提到python 3的f-string之后,我在python 3.7.2下测试了以下代码:

import timeit
print('format:', timeit.timeit("'{}{}{}'.format(1, 1.23, 'hello')"))
print('%:', timeit.timeit("'%s%s%s' % (1, 1.23, 'hello')"))
print('f-string:', timeit.timeit("f'{1}{1.23}{\"hello\"}'"))

结果:

format: 0.8331376779999999
%: 0.6314778750000001
f-string: 0.766649943

似乎f-string仍然比%慢,但比格式好。