Python 3 字节格式化

80

在Python 3中,可以这样格式化字符串:

"{0}, {1}, {2}".format(1, 2, 3)

但是如何格式化字节?

b"{0}, {1}, {2}".format(1, 2, 3)

引发了 AttributeError: 'bytes' object has no attribute 'format' 错误。

如果 bytes 没有 format 方法,如何对其进行格式化或"重写"呢?

6个回答

53
自从Python 3.5版本开始,%格式化方式也可以用于bytes了!这是由Ethan Furman撰写的PEP 461的一部分。
PEP: 461
Title: Adding % formatting to bytes and bytearray
Version: $Revision$
Last-Modified: $Date$
Author: Ethan Furman <ethan at stoneleaf.us>
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 2014-01-13
Python-Version: 3.5
Post-History: 2014-01-14, 2014-01-15, 2014-01-17, 2014-02-22, 2014-03-25,
               2014-03-27
Resolution:


Abstract
========

This PEP proposes adding % formatting operations similar to Python 2's ``str``
type to ``bytes`` and ``bytearray`` [1]_ [2]_.


Rationale
=========

While interpolation is usually thought of as a string operation, there are
cases where interpolation on ``bytes`` or ``bytearrays`` make sense, and the
work needed to make up for this missing functionality detracts from the overall
readability of the code.


Motivation
==========

With Python 3 and the split between ``str`` and ``bytes``, one small but
important area of programming became slightly more difficult, and much more
painful -- wire format protocols [3]_.

This area of programming is characterized by a mixture of binary data and
ASCII compatible segments of text (aka ASCII-encoded text).  Bringing back a
restricted %-interpolation for ``bytes`` and ``bytearray`` will aid both in
writing new wire format code, and in porting Python 2 wire format code.

Common use-cases include ``dbf`` and ``pdf`` file formats, ``email``
formats, and ``FTP`` and ``HTTP`` communications, among many others.

2014年3月27日,Guido van Rossum接受了PEP 461:

接受了。祝贺你成功调解了这场相当具有争议性的讨论,还容忍了我最后一刻的顽固!

由此,我们可以明显地得出结论:%不再被计划弃用(正如在Python 3.1中宣布的那样)。


31

另一种方法是:

"{0}, {1}, {2}".format(1, 2, 3).encode()

在 IPython 1.1.0 和 Python 3.2.3 上测试通过。


17
如果你的格式化参数是字节类型,这个方法将无法正常工作。 - user3467349
6
如果你需要插入Unicode不支持的硬字节码到数据流中,那么这种方法就不可行。 - EvertW

18
我发现在Python 3.6.2中使用%b效果最佳,它应该适用于和"":
print(b"Some stuff %b. Some other stuff" % my_byte_or_unicode_string)

2
应该使用%b而不是%a来表示字节字符串,否则会包含'b'前缀。 - panda-34
然而在Python 2.7.16中它无法工作,因此它不具备向后兼容性。 - pts
2
它不支持Unicode字符串,只支持b''。 - Maxim Suslov

18

有趣的是,像你展示的那样,字节序列似乎不支持.format()

你可以使用在这里建议的.join()方法。

b", ".join([b'1', b'2', b'3'])

Python之父亲自证实,使用.join()方法比.format()方法速度更快。

证明链接:http://bugs.python.org/msg180449


谢谢!BDFL的消息也很棒。然而,这并不能解决浮点数的格式问题。除了str(some_bytes).encode()之外,是否还有其他方法值得探究呢? - Ecir Hana
明白了。.format() 方法用于字节似乎正在3.4+版本中被纳入考虑。 - mechanical_meat
1
@bernie:但是对象的__format__方法和内置的format返回的是str类型。那么在处理bytes和编码时会有什么影响呢? - Eryk Sun
4
@bernie: bytes.format() pep已被撤销。相反,Python 3.5引入了printf-style formatting (%-interpolation) - jfs

13

对于Python 3.6+,您可以使用这种简洁明了的语法:

f'foo {bar}'.encode() # a byte string

4
这段代码对字符串 str 进行格式化,不适用于字节串 bytes。例如,如果 bar 是一个 bytes 对象,则无法得到预期的结果。或者,如果您想在格式化字符串中放置非 ASCII 字节值。 - interjay
@interjay 当然有各种情况,我的解决方案可能无法提供帮助,包括你提到的那个。但这并不否认事实,即仍有其他情况,包括我遇到的情况,可以使用这个解决方案。 - Nurbol Alpysbayev
1
这应该是被接受的答案,因为它描述了最简单和最好的解决方案。 - SLDem
4
这实际上是Schcriher的回答的重复,并且存在完全相同的问题。 - wjandrea

-4

我发现这个可行。

a = "{0}, {1}, {2}".format(1, 2, 3)

b = bytes(a, encoding="ascii")

>>> b
b'1, 2, 3'

3
这是 Schcriher 的回答 的副本,只是使用了不同的编码过程。 - wjandrea

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接