Python:如何强制“print”使用__unicode__而非__str__,或自然“print”消息而无需显式调用unicode()

7 投票
1 回答
4245 浏览
提问于 2025-04-17 06:49

基本上,我想用一个叫做Bottle的类来创建实例,比如说 class Bottle(object):...,然后在另一个模块中能够简单地“打印”任何实例,而不需要去修改代码来专门调用字符编码的程序。

总结一下,当我尝试:

obj=Bottle(u"味精")
print obj

或者进行“就地”打印:

print Bottle(u"味精")

我得到的结果是:

"UnicodeEncodeError: 'ascii' codec can't encode characters"

类似的StackOverflow问题:

¢ 目前还不能切换到python3. ¢

如果能提供一个解决方案或提示(以及解释),告诉我如何进行就地的utf-8打印(就像下面的类U那样成功)我会非常感激。:-)

谢谢 N

--

示例代码:

-------- 8>< - - - - cut here - - - -

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def setdefaultencoding(encoding="utf-8"):
  import sys, codecs

  org_encoding = sys.getdefaultencoding()
  if org_encoding == "ascii": # not good enough
    print "encoding set to "+encoding
    sys.stdout = codecs.getwriter(encoding)(sys.stdout)
    sys.stderr = codecs.getwriter(encoding)(sys.stderr)

setdefaultencoding()

msg=u"味精" # the message!

class U(unicode): pass

m1=U(msg)

print "A)", m1 # works fine, even with unicode, but

class Bottle(object):
  def __init__(self,msg): self.msg=msg
  def __repr__(self): 
    print "debug: __repr__",self.msg
    return '{{{'+self.msg+'}}}'
  def __unicode__(self): 
    print "debug: __unicode__",self.msg
    return '{{{'+self.msg+'}}}'
  def __str__(self): 
    print "debug: __str__",self.msg
    return '{{{'+self.msg+'}}}'
  def decode(self,arg): print "debug: decode",self.msg
  def encode(self,arg): print "debug: encode",self.msg
  def translate(self,arg): print "debug: translate",self.msg

m2=Bottle(msg)

#print "B)", str(m2)
print "C) repr(x):", repr(m2)
print "D) unicode(x):", unicode(m2)
print "E)",m2 # gives:  UnicodeEncodeError: 'ascii' codec can't encode characters

-------- 8>< - - - - cut here - - - - Python 2.4 输出:

encoding set to utf-8
A) 味精
C) repr(x): debug: __repr__ 味精
{{{\u5473\u7cbe}}}
D) unicode(x): debug: __unicode__ 味精
{{{味精}}}
E) debug: __str__ 味精
Traceback (most recent call last):
  File "./uc.py", line 43, in ?
    print "E)",m2 # gives:  UnicodeEncodeError: 'ascii' codec can't encode characters
UnicodeEncodeError: 'ascii' codec can't encode characters in position 3-4: ordinal not in range(128)

-------- 8>< - - - - cut here - - - - Python 2.6 输出:

encoding set to utf-8
A) 味精
C) repr(x): debug: __repr__ 味精
Traceback (most recent call last):
  File "./uc.py", line 41, in <module>
    print "C) repr(x):", repr(m2)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 3-4: ordinal not in range(128)

相关问题:

1 个回答

6

如果你使用 sys.stdout = codecs.getwriter(encoding)(sys.stdout),那么你在用 print 打印的时候应该传入 Unicode 字符串:

>>> print u"%s" % Bottle(u"魯賓遜漂流記")
debug: __unicode__ 魯賓遜漂流記
{{{魯賓遜漂流記}}}

正如 @bobince 在评论中提到的:尽量避免以这种方式改变 sys.stdout,否则可能会影响到任何依赖 sys.stdout 的库代码,这些代码可能不支持打印 Unicode 字符串。

一般来说:

__unicode__() 应该返回 Unicode 字符串:

def __init__(self, msg, encoding='utf-8'):
    if not isinstance(msg, unicode):
       msg = msg.decode(encoding)
    self.msg = msg

def __unicode__(self):
    return u"{{{%s}}}" % self.msg

__repr__() 应该返回适合 ASCII 的 str 对象:

def __repr__(self):
    return "Bottle(%r)" % self.msg

__str__() 应该返回 str 对象。可以选择性地添加 encoding 来说明使用了什么编码。这里没有好的方法来选择编码:

def __str__(self, encoding="utf-8")
    return self.__unicode__().encode(encoding)

定义 write() 方法:

def write(self, file, encoding=None):
    encoding = encoding or getattr(file, 'encoding', None)
    s = unicode(self)
    if encoding is not None:
       s = s.encode(encoding)
    return file.write(s)

这个方法应该处理文件有自己编码或者直接支持 Unicode 字符串的情况。

撰写回答