打印物体和unicode,引擎盖下有什么?有什么好的指导方针?

Tho*_*fin 6 python printing unicode stdout

我正在努力进行打印和unicode转换.这是在2.5 windows解释器中执行的一些代码.

>>> import sys
>>> print sys.stdout.encoding
cp850
>>> print u"é"
é
>>> print u"é".encode("cp850")
é
>>> print u"é".encode("utf8")
?®
>>> print u"é".__repr__()
u'\xe9'

>>> class A():
...    def __unicode__(self):
...       return u"é"
...
>>> print A()
<__main__.A instance at 0x0000000002AEEA88>

>>> class B():
...    def __repr__(self):
...       return u"é".encode("cp850")
...
>>> print B()
é

>>> class C():
...    def __repr__(self):
...       return u"é".encode("utf8")
...
>>> print C()
?®

>>> class D():
...    def __str__(self):
...       return u"é"
...
>>> print D()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 0: ordinal not in range(128)

>>> class E():
...    def __repr__(self):
...       return u"é"
...
>>> print E()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 0: ordinal not in range(128)
Run Code Online (Sandbox Code Playgroud)

因此,当打印一个unicode字符串时,它不是__repr__()调用和打印的函数.
但是,当打印对象__str__()__repr__()(如果__str__未实现)被调用时,则不会__unicode__().两者都无法返回unicode字符串.
但为什么?为什么如果__repr__()__str__()返回一个unicode字符串,它不应该与我们打印unicode字符串时的行为相同吗?我换句话说:为什么print D()不同print D().__str__()

我错过了什么吗?

这些示例还显示,如果要打印以unicode字符串表示的对象,则必须将其编码为对象字符串(类型为str).但是为了良好的打印(避免使用"├®"),它取决于sys.stdout编码.
所以,我必须添加u"é".encode(sys.stdout.encoding)我的每个的__str____repr__方法?或者返回repr(u"é")?如果我使用滚边怎么办?是编码相同sys.stdout吗?

我的主要问题是使类"可打印",即print A()打印完全可读的内容(不使用\ x***unicode字符).以下是需要修改的错误行为/代码:

class User(object):
    name = u"Luiz Inácio Lula da Silva"
    def __repr__(self):
        # returns unicode
        return "<User: %s>" % self.name
        # won't display gracefully
        # expl: print repr(u'é') -> u'\xe9'
        return repr("<User: %s>" % self.name)
        # won't display gracefully
        # expl: print u"é".encode("utf8") -> print '\xc3\xa9' -> ?®
        return ("<User: %s>" % self.name).encode("utf8")
Run Code Online (Sandbox Code Playgroud)

谢谢!

Ale*_*lli 8

Python 对给定的函数和方法没有很多语义类型约束,但它有一些,这里有一个:( __str__在Python 2.*中)必须返回一个字节字符串.像往常一样,如果找到'ascii'需要字节字符串的unicode对象,则会尝试使用当前的默认编码(通常)来尝试从相关的unicode对象生成所需的字节字符串.

对于此操作,任何给定文件对象的编码(如果有的话)都是无关紧要的,因为从中返回的内容__str__可能即将被打印,或者可能会受到完全不同且无关的处理.你打电话的目的__str__与呼叫本身及其结果无关; 通常,Python在确定操作的语义时不会考虑操作的"未来上下文"(操作完成后将对结果执行的操作).

这是因为Python并不总是知道你未来的意图,并试图尽量减少意外. print str(x)并且s = str(x); print s(在一次吞咽中对两次进行的操作相同)尤其必须具有相同的效果; 如果是第二种情况,如果str(x)无法有效地产生字节串(例如,x.__str__()不能),则会出现异常,因此在其他情况下也应该发生异常.

print本身(因为2.4,我相信),当提供一个unicode对象时,会考虑.encoding目标流的属性(如果有的话)(默认情况下sys.stdout); 尚未连接到任何给定目标流的其他操作不会 - 而且str(x)(即x.__str__())就是这样的操作.

希望这有助于说明令你烦恼的行为的原因......

编辑:OP现在澄清"我的主要问题是使类"可打印",即打印A()打印完全可读的内容(不使用\ x***unicode字符)." 这是我认为最适合该特定目标的方法:

import sys

DEFAULT_ENCODING = 'UTF-8'  # or whatever you like best

class sic(object):

    def __unicode__(self):  # the "real thing"
        return u'Pel\xe9'

    def __str__(self):      # tries to "look nice"
        return unicode(self).encode(sys.stdout.encoding or DEFAULT_ENCODING,
                                    'replace')

    def __repr__(self):     # must be unambiguous
        return repr(unicode(self))
Run Code Online (Sandbox Code Playgroud)

也就是说,这种方法侧重于__unicode__作为类的实例自我格式化的主要方式 - 但是由于(在Python 2中)print调用__str__,它具有一个委托,__unicode__它在编码方面可以做到最好.不完美,但随后Python 2的print声明远非完美;-).

__repr__就其本身而言,必须努力明确,即不要以牺牲模糊性为代价来"看起来不错"(理想情况下,在可行的情况下,它应返回一个字节串,如果传递给它eval,将使实例等于现在的......远非总是可行的,但缺乏模糊性是和之间区别的绝对核心,我强烈建议尊重这种区别!).__str____repr__