我正在努力进行打印和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")
谢谢!
答案 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'之前发生异常。