【问题标题】:Supporting python 2 and 3: str, bytes or alternative支持 python 2 和 3:str、bytes 或替代
【发布时间】:2016-03-11 14:36:56
【问题描述】:

我有一个 Python2 代码库,它广泛使用 str 来存储原始二进制数据。我想同时支持 Python2 和 Python3。

Python2 中的bytesstr 的别名)类型和Python3 中的bytes 完全不同。它们采用不同的参数来构造,索引到不同的类型,并具有不同的strrepr

统一两个 Python 版本的代码,使用单一类型存储原始数据的最佳方法是什么?

【问题讨论】:

  • 为什么不坚持str?版本之间是一样的吧?
  • @zondo:不,他们不是。 Python 3 中的 str 与 2 中的 unicode 大致相同。您不能在 Python 3 中将原始二进制数据存储在 str 中。
  • 在两者中使用 b'..' 前缀来定义文字,并使用像 six 这样的桥接库来处理其余情况。

标签: python python-2.7 python-3.x


【解决方案1】:

python-future 包有一个 Python3 字节类型的 backport

>>> from builtins import bytes  # in py2, this picks up the backport
>>> b = bytes(b'ABCD')

这在Python 2 和 Python 3 中都提供了 Python 3 接口。在 Python 3 中,它是内置的 bytes 类型。在 Python 2 中,它是str 类型之上的兼容层。

【讨论】:

  • 这是最好的方法 - 只允许编写惯用的 Python 3 代码。 +1 提到six,这使得代码看起来像废话。
【解决方案2】:

我不知道你想在哪些部分使用字节,我几乎总是使用字节数组,这就是我从文件读取时的方式

with open(file, 'rb') as imageFile:
    f = imageFile.read()
    b = bytearray(f)

我从我正在进行的一个项目中取出了它,它适用于 2 和 3。也许你可以看看?

【讨论】:

  • 这不是处理这个问题的一种非常有效的方法。许多项目设法在 2 中使用 str 在 3 中使用 bytes
  • bytearray 是可变的,不幸的是。不变性对我很重要
【解决方案3】:

如果您的项目小而简单,请使用six

否则我建议有两个独立的代码库:一个用于 Python 2,一个用于 Python 3。起初这听起来像是很多不必要的工作,但最终它实际上更容易维护。

如果您决定在一个代码库中同时支持两个 python,您的项目可能会变成什么样子,请查看 google 的 protobuf。围绕代码的许多经常违反直觉的分支,被修改的抽象只是为了允许黑客攻击。而且随着项目的发展,它不会变得更好:截止日期会影响代码的质量。

使用两个独立的代码库,您只需应用几乎相同的补丁程序,如果您想要一个代码库,与前面的工作相比,这不是很多工作。一旦你的包的 Python 2 用户数量下降,完全迁移到 Python 3 会更容易。

【讨论】:

  • And you will likely drop Python 2 version in a year or so anyway 你怎么能这么肯定?就我个人而言,如果有的话,我将在很多年内都不会接触 3.x,而且我认识很多有相同感受的人。不想或不能使用 Python 3.x 的原因有很多。
  • 我会从我的答案中删除这个。无意冒犯。如果您想讨论为什么新项目不需要 Python 2,让我们在聊天中进行。
  • 大型项目的独立代码库?那是无法维护的。
  • @MartijnPieters 我同意,这在很大程度上取决于项目的代码和开发周期。对于社区支持的东西,这将是困难的。另一方面,统一的代码库也可能变得不可维护。这两种方法都需要仔细处理每个更改。这正是您想花时间在哪里:过时且难以调试或分离的统一代码库,Python 3 版本可以在哪里独立发展?
  • @Kentzo:像requests 和 Pyramid 这样的项目管理得很好。在两个 python 上运行测试的持续集成是关键。
【解决方案4】:

假设您只需要支持 Python 2.6 和更新版本,您可以简单地将 bytes 用于字节。使用b 字面量创建字节对象,例如b'\x0a\x0b\x00'。处理文件时,请确保模式包含b(如open('file.bin', 'rb'))。
请注意,迭代和元素访问是不同的。在这些情况下,您可以编写代码以使用块。而不是b[0] == 0(Python 3)或b[0] == b'\x00'(Python 2)写b[0:1] == b'\x00'。其他选项是使用bytearray(当字节是可变的)或辅助函数。

在 Python 2 中字符串应该是unicode,独立于 Python 3 移植;否则代码在遇到非 ASCII 字符时可能会出错。在 Python 3 中等价于 str
使用u 字面量创建字符串(例如u'Düsseldorf')和/或确保每个文件都以from __future__ import unicode_literals 开头。必要时通过以# encoding: utf-8 开头的文件声明文件编码。
使用io.open 从文件中读取字符串。对于网络代码,获取字节并在它们上调用decode以获取字符串。

如果您需要支持 Python 2.5 或 3.2,请查看 six 以转换文字。

添加大量断言以确保对字符串进行操作的函数不会获取字节,反之亦然。像往常一样,一个具有 100% 覆盖率的良好测试套件会有很大帮助。

【讨论】:

    猜你喜欢
    • 2019-10-31
    • 1970-01-01
    • 2018-11-12
    • 1970-01-01
    • 2017-04-25
    • 2014-03-08
    • 1970-01-01
    • 1970-01-01
    • 2020-02-15
    相关资源
    最近更新 更多