【问题标题】:Unicode and overriding '__str__'Unicode 和覆盖 '__str__'
【发布时间】:2015-09-11 22:10:23
【问题描述】:

我收到一个 unicode 错误只有在覆盖我的类的__str__ 方法时。怎么回事?

Test.py:

class Obj(object):

    def __init__(self):
        self.title = u'\u2018'

    def __str__(self):
        return self.title


print "1: ", Obj().title
print "2: ", str(Obj())

运行这个我得到:

$ python Test.py
1:  ‘
2: 
Traceback (most recent call last):
  File "Test.py", line 11, in <module>
    print "2: ", str(Obj())
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2018' in position 0: ordinal not in range(128)

编辑:请不要只说str(u'\u2018') 也会引发错误!(虽然这可能是相关的)。这绕过了内置方法重载的全部目的——这段代码在任何时候都不应该调用str(u'\u2018')!!

【问题讨论】:

  • str(Obj().title) 具有相同的行为,它与 __str__ 无关
  • afaik __str__ 有合同义务返回 ascii 字节而不是 unicode,不这样做可能会导致问题...尝试 def __str__(self):return self.title.encode("utf8")
  • @DilithiumMatrix 事实是错误来自title 中的unicode,而不是因为__str__ 的重载,stackoverflow.com/help/mcve 会突出显示这一点,问题是重复的
  • @DilithiumMatrix 重载方法中不会发生。 str(Obj()) 将调用str(Obj().__str__()),它变成str(u'\u2018') 并抛出UnicodeEncodeError。我不明白你为什么对给你答案的人如此敌视。
  • 你是敌对的,因为你对 Python 的工作原理知之甚少,却对帮助你的人大喊大叫,投反对票。祝你好运。

标签: python string unicode


【解决方案1】:

您使用的是 Python 2.x。 str() 调用__str__ 并希望您返回一个字符串,即str。但你不是;您正在返回一个 unicode 对象。所以str() 很有帮助地尝试将其转换为str,因为这是str() 应该返回的内容。

现在,在 Python 2.x 中,字符串是字节序列,不是代码点,因此 Python 正在尝试将您的 Unicode 对象转换为字节序列。由于您没有(在这种情况下也不能)指定在创建字符串时使用什么编码,Python 使用 ASCII 的默认编码。这会失败,因为 ASCII 不能代表字符。

可能的解决方案:

  1. 使用 Python 3,其中所有字符串都是 Unicode。这将为您提供一系列有趣的不同事物来让您一头雾水,但这不会是其中之一。

  2. 在将对象转换为字符串时,覆盖 __unicode__() 而不是 __str__() 并使用 unicode() 而不是 str()。您仍然有一个问题(与 Python 3 共享),即如何将其转换为可以正确输出的字节序列。

  3. 找出您的终端使用的编码(即sys.stdout.encoding)并让__str__()在返回之前将Unicode对象转换为该编码。请注意,仍然不能保证字符在该编码中是可表示的;例如,您不能将示例字符串转换为默认的 Windows 终端编码。在这种情况下,您可以回退到例如unicode-escape 编码,如果您在尝试转换为输出编码时遇到异常。

【讨论】:

  • 谢谢!这是非常清楚的。 str() 似乎很奇怪,除了调用__str__() 还尝试以这种方式进行转换。例如,如果def __str__(self): return 5,那么这会给出错误TypeError: __str__ returned non-string (type int) --- 即它不只是返回str(5)(工作正常);就我而言,它也不会给出错误returned non-string (type unicode) 或其他东西。
  • 是的,我认为当他们添加 unicode 时,他们试图提供帮助,但存在这样的不一致之处。
【解决方案2】:

问题是 str() 无法处理 u'\u2018' (unicode),因为它试图将其转换为 ascii 并且没有 ascii 字符。

>>> str(u'\u2018')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2018' in position 0: ordinal not in range(128)
>>> 

您可以查看this 了解更多信息...

【讨论】:

  • 嗯,是这样,但是覆盖方法返回 self.title 并且在 init 覆盖中设置为 str(u'\u2018')....
  • 您的问题是您返回一个unicode 对象,您必须返回一个ascii str。如果您不喜欢它,请使用 Python 3。
  • @DilithiumMatrix 错误。 print函数可以直接打印unicode对象。
  • 在您的第一次打印中,您将一个 unicode 对象传递给 print 函数。 print 函数不需要进行任何转换来输出该对象。在第二行 您正在呼叫str
  • 是的,因为这永远不会创建 str!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-07
  • 2019-12-18
  • 2012-07-18
  • 2015-02-08
相关资源
最近更新 更多