【问题标题】:Python difference between print obj and print obj.__str__() [at least with Unicode?]print obj 和 print obj.__str__() 之间的 Python 区别 [至少使用 Unicode?]
【发布时间】:2012-07-04 06:59:02
【问题描述】:

我了解到调用print obj 会调用obj.__str__(),而obj.__str__() 又会返回一个字符串以打印到控制台。现在我遇到了一个 Unicode 问题,我无法打印任何非 ascii 字符。我得到了典型的“ascii 超出范围”的东西。

在试验以下工作时:

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

两个函数的作用完全相同(__str__() 只返回self.__repr__())。什么不起作用:

print obj

问题仅在使用超出 ascii 范围的字符时出现。最终的解决方案是__str__()中的以下内容:

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

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

操作系统是带有默认 Windows 命令提示符的 Windows 7 x64。据报道编码为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)

【问题讨论】:

  • 你运行的是什么 Python 版本?
  • 显示 obj 类的最小示例,其中包含您打印的字符串示例。
  • 您是否在寻找obj.__unicode__()
  • 您使用的是哪个版本的 Python?
  • 旁白:您可能不应该从对象外部调用__functions__。请改用str(obj)repr(obj)

标签: python unicode


【解决方案1】:

我的猜测是 print 对要打印的对象 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() 表示形式。)

【讨论】:

  • 谢谢你,这是我正在寻找的完美解释。这肯定解释了我的问题。现在,如果我 确实 想要的不仅仅是控制台输出,该怎么办。什么是好的解决方案?我的方法是像这样定义第二个参数:__str__(self, encoding=sys.stdout.encoding)。这看起来是个好主意吗?
  • @user1461135 实际上没有将额外参数传递给__str__() 的情况,因为您不打算直接调用它。我只会在你想打电话给obj.__str__(encoding='yadda') 的任何地方使用unicode(obj).encode('yadda'),它不太可能让人们感到惊讶。
【解决方案2】:

首先,如果您查看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

【讨论】:

  • 从技术上讲,在最新版本的 Python (3.x) 中,这种区别不再存在。
猜你喜欢
  • 1970-01-01
  • 2014-09-09
  • 1970-01-01
  • 2011-04-02
  • 1970-01-01
  • 2013-09-06
  • 2013-10-27
  • 2020-08-10
相关资源
最近更新 更多