__repr__() 函数的最佳输出类型和编码实践?

Posted

技术标签:

【中文标题】__repr__() 函数的最佳输出类型和编码实践?【英文标题】:Best output type and encoding practices for __repr__() functions? 【发布时间】:2011-04-07 08:49:12 【问题描述】:

最近,我在__repr__()format() 和编码方面遇到了很多麻烦。 __repr__() 的输出应该编码还是 unicode 字符串? 在 Python 中,__repr__() 的结果是否有最佳编码?我要输出的确实有非 ASCII 字符。

我使用 Python 2.x,并且想编写可以轻松适应 Python 3 的代码。程序因此使用

# -*- coding: utf-8 -*-
from __future__ import unicode_literals, print_function  # The 'Hello' literal represents a Unicode object

以下是一些一直困扰我的其他问题,我正在寻找解决这些问题的解决方案:

    应该可以打印到 UTF-8 终端(我将 sys.stdout.encoding 设置为 UTF-8,但最好是其他情况也可以)。 将输出通过管道传输到文件(以 UTF-8 编码)应该可以工作(在这种情况下,sys.stdout.encodingNone)。 我的许多__repr__() 函数的代码目前有很多return ….encode('utf-8'),这很重。有什么坚固而轻便的东西吗? 在某些情况下,我什至有像return ('<>'.format(repr(x).decode('utf-8'))).encode('utf-8') 这样的丑陋野兽,即对象的表示被解码,放入格式化字符串,然后重新编码。我想避免这种复杂的转换。

为了编写简单的__repr__() 函数,在这些编码问题上表现得很好,您建议做什么?

【问题讨论】:

【参考方案1】:

在 Python2 中,__repr__(和 __str__)必须返回一个字符串对象,而不是 Unicode 对象。在Python3中,情况正好相反,__repr____str__ 必须返回 unicode 对象,而不是字节(née 字符串)对象:

class Foo(object):
    def __repr__(self):
        return u'\NWHITE SMILING FACE' 

class Bar(object):
    def __repr__(self):
        return u'\NWHITE SMILING FACE'.encode('utf8')

repr(Bar())
# ☺
repr(Foo())
# UnicodeEncodeError: 'ascii' codec can't encode character u'\u263a' in position 0: ordinal not in range(128)

在 Python2 中,您真的别无选择。您必须为 __repr__的返回值。

顺便问一下,你读过PrintFails wiki吗?它可能不会直接回答 你的其他问题,但我确实发现它有助于阐明为什么 发生错误。


使用from __future__ import unicode_literals时,

'<>'.format(repr(x).decode('utf-8'))).encode('utf-8')

可以更简单的写成

str('<>').format(repr(x))

假设str 在您的系统上编码为utf-8

没有from __future__ import unicode_literals,表达式可以写成:

'<>'.format(repr(x))

【讨论】:

@EOL, 返回值必须是字符串对象。是你指向的参考手册页如何表达返回值必须是@987654336实例的约束@(unicode 对象不会是“字符串对象”)。 repr通常预计只返回 ascii(对于所有 unicode 对象,repr(uo) 的东西,例如:即使 that 只返回 ascii - 我认为没有内置 - in 或标准库类型的行为不同)但严格来说这不是语言限制,因此它不是参考手册的业务。建议的文档补丁总是受欢迎的,顺便说一句!-) @Alex:感谢 cmets。我想我的困惑来自一个事实,即在 Python 2.x 中也说“Unicode 字符串”:这就是为什么我想知道 __repr__() 是否也可以返回一个 Unicode 字符串......我一直考虑提交文档补丁。 :) @EOL,是的,我发现与字符串相关的术语(“字符串”、“unicode 字符串”、“原始字符串”……)不幸的是,在普通话语中存在歧义的风险——我 尝试始终使用严格不含歧义的术语,例如“str instance”、“unicode object”、“rawstring literal”等,但有时这种严格的术语会让人觉得生硬在非正式场合。在语言参考中,不幸的“unicode 字符串”唯一出现在 2.4.1(文字)的单个段落中:s/string/object/ 那里和“字符串”变得明确在语言参考中 i>(重要的地方)。 语言参考也有可能是故意模棱两可的,因为它应该只是CPython的参考,但对于 all 符合 Python 实现:在 Jython 和 IronPython 中,我们非常热衷于考虑完全符合的实现,all 字符串都是 Unicode(而且成本很高,而且完全反对他们各自的平台,以其他方式制作东西)。也许我们确实需要一个补充的 CPython 实现特定参考,作为实现中立的 Language 参考的附加 当然,str('&lt;&gt;').format(repr(x)) 也可以使用...见***.com/questions/809796/…【参考方案2】:

我使用如下函数:

def stdout_encode(u, default='UTF8'):
    if sys.stdout.encoding:
        return u.encode(sys.stdout.encoding)
    return u.encode(default)

那么我的__repr__ 函数如下所示:

def __repr__(self):
    return stdout_encode(u'<MyClass 0 1>'.format(self.abcd, self.efgh))

【讨论】:

【参考方案3】:

我认为装饰者可以以理智的方式管理__repr__ 的不兼容性。这是我使用的:

from __future__ import unicode_literals, print_function
import sys

def force_encoded_string_output(func):

    if sys.version_info.major < 3:

        def _func(*args, **kwargs):
            return func(*args, **kwargs).encode(sys.stdout.encoding or 'utf-8')

        return _func

    else:
        return func


class MyDummyClass(object):

    @force_encoded_string_output
    def __repr__(self):
        return 'My Dummy Class! \NWHITE SMILING FACE'

【讨论】:

漂亮的装饰器;不过,我对其进行了修改,以便在不需要时不定义_func。因此,根据您的代码,Python 2 中的__repr__ 显然可以返回一个Unicode 字符串(可能是因为unicode_literals?)。这与 unutbu 的答案相冲突……我发现文档含糊不清(docs.python.org/2/reference/datamodel.html#object.__repr__,docs.python.org/2/reference/lexical_analysis.html#index-14)。我会对这方面的任何参考信息感兴趣,只是为了确保__repr__ 返回一个 Unicode 字符串不会出现不可预见的问题。 @EOL 那么,Python 2 中的__repr__ 显然可以返回一个 Unicode 字符串 (...) 你为什么这么认为? 不错,我的错。我将删除我之前的评论,因为它不相关。

以上是关于__repr__() 函数的最佳输出类型和编码实践?的主要内容,如果未能解决你的问题,请参考以下文章

SQLAlchemy 为大型表定义 __repr__ 的最佳方法

python 的print和特殊方法 __str__和__repr__

__str__和__repr的区别

python之反射和内置函数__str____repr__

《Python》反射内置函数(__str____repr__)

python __str__ , __repr__区别