字符串格式化方法调用——与`%`格式化表达式的比较

未匹配的标注

如果仔细研究之前的章节,将注意到至少对位置引用和字典键来说,字符串的format方法看起来非常像 % 格式化表达式,特别在涉及类型码和额外格式化语法的高级应用中。事实上,在通常的用例中,特别是当在使用通用的%s“打印字符串”替换目标时,格式化表达式可能被格式化方法(即使在2.7和3.1添加了字段自动编号特性)调用更容易编码:

print('%s=%s' % ('spam', 42)) # 格式化表达式:在所有的 2.X/3.X 中
print('{0}={1}'.format('spam', 42)) # 格式化方法: 在 3.0+ 和 2.6+ 中
print('{}={}'.format('spam', 42)) # 带有自动编号: 在 3.1+ 和 2.7 中

很快就将看到:更复杂的格式化往往在复杂度上是差不多的(不管是哪种方法,困难的任务通常很困难),而且考虑到表达式的无处不在,一些人认为格式化方法是多余的。

另一方面,格式化方法也提供了一些潜在的优势。比如,原来的 % 表达式不能处理关键字,属性引用,还有二进制类型码,虽然在 % 格式字符串中的字典键引用通常可以达到类似目的。将下面的 %表达式和之前展示的等价的 format方法调用进行比较,来看看这两个技术是如何重叠的:

>>> '%s, %s and %s' % (3.14, 42, [1, 2]) # 任意类型
'3.14, 42 and [1, 2]'

>>> 'My %(kind)s runs %(platform)s' % {'kind': 'laptop', 'platform': sys.platform}
'My laptop runs win32'

>>> 'My %(kind)s runs %(platform)s' % dict(kind='laptop', platform=sys.platform)
'My laptop runs win32'

>>> somelist = list('SPAM')
>>> parts = somelist[0], somelist[-1], somelist[1:3]
>>> 'first=%s, last=%s, middle=%s' % parts
"first=S, last=M, middle=['P', 'A']"

当更复杂的格式化被应用时,这两个技术差不多一样复杂,虽然如果将下面例子和之前列出的等价的format方法调用相比,将再次发现%表达式往往要更简单和更简洁一点;在Python 3.3中:

# 添加指定的格式化

>>> '%-10s = %10s' % ('spam', 123.4567)
'spam = 123.4567'

>>> '%10s = %-10s' % ('spam', 123.4567)
' spam = 123.4567 '

>>> '%(plat)10s = %(kind)-10s' % dict(plat=sys.platform, kind='laptop')
' win32 = laptop '

# 浮点数

>>> '%e, %.3e, %g' % (3.14159, 3.14159, 3.14159)
'3.141590e+00, 3.142e+00, 3.14159'

>>> '%f, %.2f, %06.2f' % (3.14159, 3.14159, 3.14159)
'3.141590, 3.14, 003.14'

# 16、8进制,但没有2进制 (参见前面)

>>> '%x, %o' % (255, 255)
'ff, 377'

format方法有少量的 %表达式没有的高级特性,但即使更复杂的格式化在本质上仍似乎一样复杂。比如,下面例子显示了两种技术产生的相同结果,包括字段大小,对齐和各种参数引用方法:

# 在两种方法中的硬编码的引用
>>> import sys

>>> 'My {1[kind]:<8} runs {0.platform:>8}'.format(sys, {'kind': 'laptop'})
'My laptop runs win32'

>>> 'My %(kind)-8s runs %(plat)8s' % dict(kind='laptop', plat=sys.platform)
'My laptop runs win32'

在实践中,程序不太可能这样硬编码引用,而是执行提前构建一套替换数据的代码(比如,收集输入表单或数据库数据来一次性替换进HTML模板)。当在像这样的例子中考虑常见的做法时,format%表达式的比较甚至更直接:

# 在两个方法中提前构建数据
>>> data = dict(platform=sys.platform, kind='laptop')

>>> 'My {kind:<8} runs {platform:>8}'.format(**data)
'My laptop runs win32'

>>> 'My %(kind)-8s runs %(platform)8s' % data
'My laptop runs win32'

第18章将看到:在这里的方法调用中的**data是一个特殊语法,它将字典的键和值解压缩到单独的“name=value”关键字参数中,这样他们就能在格式字符串中通过名称被引用了——对函数调用工具另一个不可避免的难以理解的概念化的前向引用(译注:稍后将要解释或介绍的工具或概念的引用),它通常可能是 format 方法的另一个缺点,特别对初学者。

然而,和往常一样,随着时间的推移,Python社区将必须决定是 % 表达式,还是format方法调用,或结合两种技术的工具集更好。亲自实验这些技术来感受一下它们可以提供什么,并确保参见Python 2.6,3.0和之后版本的库引用手册来获取更多细节。


注意

在Python 3.1 和 2.7 中字符串格式的增强:添加了数字的千分位符,它每3位数作为一组,组间插入逗号。要使其生效,在类型码前添加一个逗号,并且要在宽度和精度之间(如果有的话),如下:

>>> '{0:d}'.format(999999999999)
'999999999999'
>>> '{0:,d}'.format(999999999999)
'999,999,999,999'

如果这些新版本的Python没有明确包含替换目标的位置编号,还会自动分配相对编号,然而这个扩展并不适用于所有用例,且可能抵消了格式化方法的一个主要优点——更明确的代码:

>>> '{:,d}'.format(999999999999)
'999,999,999,999'
>>> '{:,d} {:,d}'.format(9999999, 8888888)
'9,999,999 8,888,888'
>>> '{:,.2f}'.format(296999.2567)
'296,999.26'

参见3.1版本的说明来获取更多细节。还参见第25章中在formats.py中的逗号插入和金额格式化函数的例子来获得在3.1和2.7的版本之前可以被导入和使用的简单手动解决办法。在编程中很典型的是:在自己的可调用、可重用、可自定义函数中去实现新功能,而非依赖于一套固定内置工具是相当简单易懂的:

>>> from formats import commas, money
>>> '%s' % commas(999999999999)
'999,999,999,999'
>>> '%s %s' % (commas(9999999), commas(8888888))
'9,999,999 8,888,888'
>>> '%s' % money(296999.2567)
'$296,999.26'

而且和往常一样,像这样的简单函数还可以被用到更高级的情形下,如在第4章中见到的且将在随后章节中完整学习的迭代工具:

>>> [commas(x) for x in (9999999, 8888888)]
['9,999,999', '8,888,888']
>>> '%s %s' % tuple(commas(x) for x in (9999999, 8888888))
'9,999,999 8,888,888'
>>> ''.join(commas(x) for x in (9999999, 8888888))
'9,999,9998,888,888'

不管结果好坏,Python开发者常似乎倾向于添加特殊用例的内置工具而非通用开发技术——在下一章节中将探索的一种妥协。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~