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

时间:2010-08-24 13:46:09

标签: python unicode printing 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)

因此,当打印出一个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")

谢谢!

2 个答案:

答案 0 :(得分:8)

Python在给定的函数和方法上没有许多语义类型约束,但它有一些,而这里是其中之一:__str__(在Python 2. *)中必须返回一个字节字符串。像往常一样,如果找到需要字节字符串的unicode对象,则会尝试使用当前的默认编码(通常为'ascii')来尝试从相关的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))

也就是说,这种方法侧重于__unicode__作为类的实例格式化自己的主要方式 - 但是因为(在Python 2中)print调用__str__而是一个代表__unicode__的代表在编码方面做得最好。不完美,但是Python 2的print语句无论如何都远非完美; - )。

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

答案 1 :(得分:0)

我认为你的sys.getdefaultencoding()仍然是'ascii'。而且我认为只要应用了对象的str()或repr(),就会使用它。你可以用sys.setdefaultencoding()改变它。但是,只要您写入流,无论是STDOUT还是文件,您都必须遵守其编码。这也适用于外壳上的管道,IMO。我假设'print'遵循STDOUT编码,但在构造其参数时调用'print'之前发生异常。