2010-09-02 105 views
65

最近,我在__repr__()format()和编码方面遇到了很多麻烦。 __repr__()的输出是否应该被编码或是一个unicode字符串? Python中的__repr__()的结果是否有最好的编码?我想要输出的确有非ASCII字符。__repr __()函数的最佳输出类型和编码实践?

我使用Python 2.x和要编写能够很容易地适应到Python 3代码因此,本方案采用

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

下面是已困扰了我一些额外的问题,而且我我想找的是解决他们的解决方案:

  1. 打印到UTF-8的终端应该工作(我有sys.stdout.encoding设置为UTF-8,但它是最好的,如果其他情况下,工作太)。
  2. 管道输出到一个文件(UTF-8编码)应该工作(在这种情况下,sys.stdout.encodingNone)。
  3. 我的代码很多__repr__()功能目前有很多return ….encode('utf-8'),这很重。有没有什么健壮和轻量?
  4. 在某些情况下,我甚至有丑陋的野兽,比如return ('<{}>'.format(repr(x).decode('utf-8'))).encode('utf-8'),即对象的表示被解码,放入一个格式化字符串,然后重新编码。我想避免这种复杂的转变。

对于编写简单的__repr__()函数,您会建议如何处理这些编码问题?

回答

41

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

class Foo(object): 
    def __repr__(self): 
     return u'\N{WHITE SMILING FACE}' 

class Bar(object): 
    def __repr__(self): 
     return u'\N{WHITE 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您的系统上。

'<{}>'.format(repr(x)) 
+0

这将是很好,如果文档提到这个:)(http://docs.python.org/reference/datamodel.html#basic-customization没有)......反正......你会说问题中第4点的方法很繁琐但是必要的,对吗? – EOL 2010-09-02 14:11:54

+0

EOL:假设Python2,'repr(x)'必须返回一个编码字符串。如果它使用utf-8编码,那么'repr(x).decode('utf8')。encode('utf8')'不应该是必需的。 如果'repr(x)'使用其他编码进行编码,'repr(x).decode('utf8')'将会失败(使用UnicodeDecodeError)或产生伪造结果,或者可能是幸运偶然正确解码。因此,AFAIK,'repr(x).decode('utf8')。encode('utf8')' 应该永远不需要。你能提供一个例子吗? – unutbu 2010-09-02 14:23:09

+2

@EOL,**返回值必须是一个字符串对象**是您指向的参考手册页如何表达返回值必须是“str”实例的约束条件(unicode对象不会是“a字符串对象“)。 'repr'通常只会返回ascii(所有unicode对象的'repr(uo)'的东西,例如:甚至_that_只返回ascii - 我认为没有内置或标准库类型的行为),但严格来说这不是语言限制,所以它不是参考手册的业务。建议的文档补丁总是欢迎,顺便说一句! - ) – 2010-09-02 14:29:01

1

我使用如下的功能:

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

然后我__repr__功能看起来像这样:

没有from __future__ import unicode_literals,表达式可以作为写

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

我认为装修工可以管理__repr__ incomp理智的方式。下面是我使用:

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! \N{WHITE SMILING FACE}' 
+0

好的装饰者;不过,我修改了它,这样'_func'在不需要时就没有定义。所以,根据你的代码(可能是因为'unicode_literals?),Python 2中的'__repr__'显然可以返回一个Unicode字符串。这与unutbu的答案冲突...我发现文档不明确,在此(http://docs.python.org/2/reference/datamodel.html#object.__repr__,http://docs.python.org/2/reference /lexical_analysis.html#index-14)。我会对任何有关这方面的参考信息感兴趣,只是为了确保'__repr__'返回一个Unicode字符串不会引起无法预料的问题。 – EOL 2012-12-13 03:27:06

+0

@EOL *因此,Python 2中的'__repr__'显然可以返回一个Unicode字符串(...)*您为什么这么认为? – 2013-07-10 12:41:25

+0

好,我的坏。我将删除我之前的评论,因为它不相关。 – EOL 2013-07-10 15:15:56