【问题标题】:How to write single-source compatible Python 2/3 code to write text files from in-memory strings如何编写单源兼容的 Python 2/3 代码以从内存中的字符串写入文本文件
【发布时间】:2020-10-19 10:48:55
【问题描述】:

我有一堆 Python 2.7 代码,我正在尝试使其单源代码与 Python 3 兼容,以帮助随着时间的推移从 2.7 迁移。我看到的最常见的问题是简单地将非unicode 内存内容写入磁盘。例如:

        with io.open(some_path, 'w', encoding='utf-8') as the_file:
            the_file.write(unicode(json.dumps(some_object, indent=2)))

        with io.open(some_path, 'w', encoding='utf-8') as the_file:
            the_file.write(unicode(yaml.dump(some_object, default_flow_style=False))) # From PyYAML

        with io.open(some_path, 'w', encoding='utf-8') as the_file:
            the_file.write(unicode(some_multiline_string)) # A simple string passed in, not explicitly marked up as unicode where it was declared

当然,unicode 的转换在 Python 3 下会失败,因为该类型不存在。如果我改变演员表,就像这样:

            the_file.write(str(json.dumps(some_object, indent=2)))

然后它在 Python 3 中工作,但在 Python 2 下失败,因为 strunicode 是不同的,而 file.write 需要一个 unicode 参数。虽然json.dumps 调用可以适应直接使用文件的json.dump 调用,但据我所知,yaml 转储调用不能。

理想情况下,有一种方法可以将所有正在写入的东西的类型强制转换为 file.write 想要的类型(unicode 字符串),但我找不到那是什么。我曾希望你总是能够将decode 各种形式的非unicode 字符串转换成unicode 字符串,但是Python 2 中的str 对象似乎没有decode 函数。

我发现的所有其他问题(在 Stack Overflow 和其他地方)和文档都给出了相互矛盾的建议,专注于缓冲区对象,或者只是就如何在一个版本的 Python 或另一个版本中执行此操作提供建议。我需要一个在 Python 2.7 和 3.x 中同样有效的解决方案,我希望有一个优雅的 Python 式解决方案,它不涉及在检测哪个版本正在使用的测试上进行分支。

【问题讨论】:

  • 你考虑过使用six吗?
  • 这当然是一种选择,因为我相信我们正在使用其他已经需要它的依赖项。
  • FWIW,最接近的问题 (stackoverflow.com/questions/49702626/…) 似乎问了同样的问题,但答案仅涵盖代码内 unicode 文字的情况。
  • Python 2 str 确实有一个 .decode 方法。 Python 3 str 类型没有。
  • 就像已经建议的那样,six 具有您需要的功能和包装器。您当然可以尝试自己重新发明轮子,但为什么不依赖一个广泛使用且经过良好测试的库呢?

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


【解决方案1】:

因此,根据 cmets 中的建议,我选择了 six 模块。 1.12.0 及更高版本包括six.ensure_text,这是我在问题中描述的“强制写入 [unicode] 的所有事物类型的方法”。

        with io.open(some_path, 'w', encoding='utf-8') as the_file:
            the_file.write(six.ensure_text(json.dumps(some_object, indent=2)))

        with io.open(some_path, 'w', encoding='utf-8') as the_file:
            the_file.write(six.ensure_text(yaml.dump(some_object, default_flow_style=False))) # From PyYAML

        with io.open(some_path, 'w', encoding='utf-8') as the_file:
            the_file.write(six.ensure_text(some_multiline_string)) # A simple string passed in, not explicitly marked up as unicode where it was declared

我遇到了一些版本兼容性问题(我依赖的其他 pip 模块似乎需要 six 1.11.0),但我已经解决了这些问题,并且提供的功能可以在我们所有现有的代码。

【讨论】:

    猜你喜欢
    • 2018-10-11
    • 1970-01-01
    • 2011-12-18
    • 2019-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-17
    • 2016-04-08
    相关资源
    最近更新 更多