移植到Python 3:字符串/字节格式化

3 投票
2 回答
965 浏览
提问于 2025-04-18 08:15

我正在把一个程序从Python 2移植到Python 3。现在我在处理%(插值)运算符时遇到了一些困难,特别是当值是字节类型的时候。

假设我们需要把这个表达式从Python 2移植过来:'%s: %s\r\n' % (name, value)

在移植后的程序中,namevalue都是字节类型(bytes)。结果也应该是字节类型。因为在Python 3中,二进制插值只在Python 3.5中计划实现(PEP 460)。所以,我不太确定我理解得对不对,但解决这个问题的方法只有两种——拼接或者在合适的地方进行字符串的编码/解码:

>>> name = b'Host'
>>> value = b'example.com'
>>> # Decode bytes and encode resulting string.
>>> ('%s: %s\r\n' % (name.decode('ascii'), value.decode('ascii'))).encode('ascii')
b'Host: example.com\r\n'
>>> # ... or just use concatenation.
>>> name + b': ' + value + b'\r\n'
b'Host: example.com\r\n'

就我个人而言,这两种解决方案都有点难看。有没有什么约定或者建议,关于当值是bytes时,如何进行字符串格式化移植呢?

注意,2to3工具不应该被使用,并且程序应该在Python 2和3下都能运行。

2 个回答

1

在这个特定的情况下,解码-格式化-编码的解决方案可能看起来有点复杂,但其实这是一个常见的做法。

这个方法的核心思想是,你在内部只处理Unicode字符串,而在接收或发送数据时才进行解码和编码。这个方法在Ned Batchelder的《实用Unicode》中被称为“Unicode三明治”。

另外,根据具体情况,你可能只需要改变一下namevaluebytes对象这一点。

2

我为CPython开发了一个叫做 bttf 的库,计划添加一些移植功能;目前它可以把Python 3.5的字节格式化代码应用到Python 3.3和3.4中:

所以,在使用之前,你会看到:

>>> b'I am bytes format: %s, %08d' % (b'asdf', 42)
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for %: 'bytes' and 'tuple'

而使用 bttf 后,你会看到:

>>> from bttf import install
>>> install('bytes_mod')
>>> b'I am bytes format: %s, %08d' % (b'asdf', 42)
b'I am bytes format: asdf, 00000042'

__future__ 不同,这个补丁是对整个解释器生效的。

撰写回答