2012-07-03 55 views
9

我被告知要调用print obj将调用obj.__str__(),这将返回一个字符串以打印到控制台。现在我遇到了一个Unicode问题,我无法打印任何非ascii字符。我得到了典型的“ascii超出范围”的东西。打印obj和打印obj .__ str __之间的Python区别__()[至少使用Unicode?]

虽然尝试以下工作:

print obj.__str__() 
print obj.__repr__() 

随着做的正是这两个功能相同(__str__()刚刚返回self.__repr__())。什么没有工作:

print obj 

问题只发生在使用字符超出ascii范围。最终的解决方案是为以下在__str__()

return self.__repr__().encode(sys.stdout.encoding) 

现在,它适用于所有的部件。我现在的问题是:区别在哪里?它为什么现在工作?如果没有任何工作,我会得到,为什么现在可以工但为什么只有最上面的部分是工作的,而不是底部。

操作系统是Windows 7 x64,具有默认的Windows命令提示符。编码也被报告为cp850。这是理解python的一个普遍问题。我的问题已经解决了,但我并不是100%满意,主要是因为现在调用str(obj)会产生一个字符串,而不是以我想要的方式进行编码。

# -*- coding: utf-8 -*- 
class Sample(object): 

    def __init__(self): 
     self.name = u"üé" 

    def __repr__(self): 
     return self.name 

    def __str__(self): 
     return self.name 

obj = Sample() 
print obj.__str__(), obj.__repr__(), obj 

删除最后的obj它的工作原理。保持它,并将它与

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128) 
+0

什么Python版本是你在跑? –

+0

用您打印的字符串样本显示obj类的最小示例。 –

+2

你是否在寻找'obj .__ unicode __()'? –

回答

4

我的猜测是,打印确实像一个对象obj它的意思是打印如下:

  1. 检查obj是否为unicode。如果是这样,编码到sys.stdout.encoding并打印。
  2. 检查obj是否为str。如果是这样,请直接打印。
  3. 如果obj是别的,请致电str(obj)并打印。

第1步是为什么print obj.__str__()适用于您的情况。

现在,str(obj)做的是:

  1. 电话obj.__str__()
  2. 如果结果是一个str,返回它
  3. 如果结果是一个unicode,它编码到"ascii"并返回
  4. 否则,东西大多无用。

调用obj.__str__()直接跳过步骤2-3,这就是为什么你没有得到编码失败。

问题不是由print如何工作引起的,而是由str()如何工作引起的。 str()忽略sys.stdout.encoding。由于它不知道你想对结果字符串做什么,所以它使用的默认编码可以被认为是任意的; ascii与任何选项一样好或不好。

为了防止此错误,请确保您按照文档要求的方式从__str__()返回str。你可以使用的Python 2.x的一个模式可能是:

class Foo(): 
    def __unicode__(self): 
     return u'whatever' 
    def __str__(self): 
     return unicode(self).encode(sys.stdout.encoding) 

(如果你确定你不需要str()表示任何东西,但打印到控制台)。

+0

谢谢,这是我正在寻找的完美解释。这肯定解释了我的问题。现在,如果我*想要拥有比控制台输出更多的东西。什么是一个好的解决方案?我的方法是定义像这样的第二个参数:'__str __(self,encoding = sys.stdout.encoding)'。这似乎是一个好主意吗? – javex

+1

@ user1461135实际情况并非如此,您可以将额外的参数传递给'__str __()',因为您不打算直接调用它。我只是使用'unicode(obj).encode'('yadda')'无论你想调用obj .__ str __(encoding ='yadda')',它都不太可能让人惊讶。 – millimoose

+0

谢谢**非常**! – javex

1

首先崩溃,如果你看一下the online documentation__str____repr__有不同的用途,并应建立不同的输出。所以从__str__调用__repr__不是最好的解决方案。

其次,print将调用__str__,不会指望得到非ASCII字符,因为,print无法猜测如何将非ASCII字符转换。

最后,在最新版本的Python 2.x中,__unicode__是为对象创建字符串表示的首选方法。 Python str versus unicode有一个有趣的解释。

因此,尝试和真正回答这个问题,你可以这样做:

class Sample(object): 

    def __init__(self): 
     self.name = u"\xfc\xe9" 

    # No need to implement __repr__. Let Python create the object repr for you 

    def __str__(self): 
     return unicode(self).encode('utf-8') 

    def __unicode__(self): 
     return self.name 
+1

从技术上讲,在真正最新版本的Python(3.x)中,这种区别不再存在。 – millimoose

+0

@millimoose你说得对。我正在考虑使用Python 2.6+ – Rodrigue

+0

'__unicode__'实际上可能比2.6更早 – Rodrigue