Python字符串格式:%与.format


Answers

模运算符(%)不能做的事,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
Question

Python 2.6引入了str.format()方法,其语法与现有的%运算符略有不同。 哪个更好,哪些情况?

  1. 以下使用每种方法,并有相同的结果,所以有什么区别?

    #!/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中出现字符串格式? 例如,如果我的日志记录级别设置为“高”,我仍然会执行下面的%操作。 如果是这样,是否有办法避免这种情况?

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



对于Python版本> = 3.6(请参阅PEP 498

s1='albha'
s2='beta'

f'{s1}{s2:>10}'

#output
'albha      beta'



作为一个便笺,你不需要通过日志记录来使用新的样式格式。 您可以将任何对象传递给logging.debuglogging.info等实现__str__魔术方法的对象。 当日志记录模块决定它必须发出你的消息对象(不管它是什么)时,它会在调用之前调用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#optimizationhttps://docs.python.org/2.6/library/logging.html#optimization




但是请小心,刚才我发现在使用现有代码中的.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参数。

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

或者如果参数字符串可以转换为一个字符串(所谓的'字节数组')







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

肯定可能会有解决方法,但您仍可以考虑立即使用format()方法。




Links