字符串格式:%与.format

Python 2.6引入了str.format()方法,其语法与现有的%运算符略有不一样。 哪一个更好,什么状况下适合? html

  1. 如下使用每种方法并具备相同的结果,那么有什么区别? python

    #!/usr/bin/python sub1 = "python string!" sub2 = "an arg" a = "i am a %s" % sub1 b = "i am a {0}".format(sub1) c = "with %(kwarg)s!" % {'kwarg':sub2} d = "with {kwarg}!".format(kwarg=sub2) print a # "i am a python string!" print b # "i am a python string!" print c # "with an arg!" print d # "with an arg!"
  2. 此外,什么时候在Python中进行字符串格式化? 例如,若是个人日志记录级别设置为“高”,执行如下%操做是否还会受到影响? 若是是这样,有办法避免这种状况吗? linux

    log.debug("some debug info: %s" % some_info)

#1楼

可是请当心,当我尝试在现有代码.format全部%替换为.format时,才发现一个问题: '{}'.format(unicode_string)将尝试对unicode_string进行编码,而且可能会失败。 正则表达式

只需查看如下Python交互式会话日志便可: 数组

Python 2.7.2 (default, Aug 27 2012, 19:52:55) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-48)] on linux2
; s='й'
; u=u'й'
; s
'\xd0\xb9'
; u
u'\u0439'

s只是一个字符串(在Python3中称为“字节数组”),而u是Unicode字符串(在Python3中称为“字符串”): 函数

; '%s' % s
'\xd0\xb9'
; '%s' % u
u'\u0439'

当您将Unicode对象做为参数提供给%运算符时,即便原始字符串不是Unicode,它也会产生一个Unicode字符串: 性能

; '{}'.format(s)
'\xd0\xb9'
; '{}'.format(u)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'latin-1' codec can't encode character u'\u0439' in position 0: ordinal not in range(256)

可是.format函数将引起“ UnicodeEncodeError”: 编码

; u'{}'.format(s)
u'\xd0\xb9'
; u'{}'.format(u)
u'\u0439'

而且仅当原始字符串为Unicode时,它才能够与Unicode参数一块儿使用。 spa

; '{}'.format(u'i')
'i'

或者参数字符串能够转换为字符串(所谓的“字节数组”) debug


#2楼

正如我今天发现的那样,经过%格式化字符串的旧方法不支持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.00000000000000000000000312312239239009009464850 0.00000000000000000000000312375239000000000000000000

固然可能有解决方法,可是您仍然能够考虑当即使用format()方法。


#3楼

附带说明,您没必要为了提升性能而在日志记录中使用新样式格式。 您能够将实现__str__ magic方法的任何对象传递给logging.debuglogging.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-styles )中进行了描述。 可是,它也能够在Python 2.6中使用( https://docs.python.org/2.6/library/logging.html#using-arbitrary-objects-as-messages )。

对使用这种技术,比的事实,它的格式风格无关,其余的优势是,它容许偷懒值,例如功能expensive_func以上。 这为Python文档中的建议提供了更优雅的替代方法: https : //docs.python.org/2.6/library/logging.html#optimization


#4楼

.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'

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


#5楼

在格式化正则表达式时, %可能会有所帮助的一种状况。 例如,

'{type_names} [a-z]{2}'.format(type_names='triangle|square')

引起IndexError 。 在这种状况下,您可使用:

'%(type_names)s [a-z]{2}' % {'type_names': 'triangle|square'}

这样能够避免将正则表达式写为'{type_names} [az]{{2}}' 。 当您有两个正则表达式时,这颇有用,其中一个正则表达式单独使用而没有格式,可是两个正则表达式的链接都已格式化。

相关文章
相关标签/搜索