Python __str__ 与 __unicode__
Posted
技术标签:
【中文标题】Python __str__ 与 __unicode__【英文标题】:Python __str__ versus __unicode__ 【发布时间】:2010-11-21 09:02:59 【问题描述】:对于何时应该实现__str__()
和__unicode__()
,是否有python 约定。我见过类覆盖__unicode__()
比__str__()
更频繁,但它似乎并不一致。是否有具体的规则,什么时候实施一个比另一个更好?是否有必要/良好的做法同时实施?
【问题讨论】:
【参考方案1】:Python 2:仅实现 __str__(),并返回 unicode。
当__unicode__()
被省略并且有人调用unicode(o)
或u"%s"%o
时,Python调用o.__str__()
并使用系统编码转换为unicode。 (见documentation of __unicode__()
。)
反之则不然。如果你实现了__unicode__()
而不是__str__()
,那么当有人调用str(o)
或"%s"%o
时,Python会返回repr(o)
。
基本原理
为什么从 __str__()
返回 unicode
会起作用?
如果__str__()
返回一个unicode,Python会使用系统编码自动将其转换为str
。
有什么好处?
① 不用担心系统编码是什么(即locale.getpreferredencoeding(…)
)。就个人而言,这不仅是混乱的,而且我认为这是系统无论如何都应该处理的事情。 ② 如果你小心,你的代码可能会与 Python 3 交叉兼容,其中__str__()
返回 unicode。
从名为 __str__()
的函数返回 unicode 是否具有欺骗性?
一点。但是,您可能已经在这样做了。如果您的文件顶部有 from __future__ import unicode_literals
,那么您很有可能在不知情的情况下返回了 unicode。
Python 3 怎么样?
Python 3 不使用__unicode__()
。但是,如果您实现 __str__()
以便它在 Python 2 或 Python 3 下返回 unicode,那么您的这部分代码将是交叉兼容的。
如果我希望 unicode(o)
与 str()
有本质区别怎么办?
实现__str__()
(可能返回str
)和__unicode__()
。我想这会很少见,但您可能想要实质上不同的输出(例如,特殊字符的 ASCII 版本,例如 ":)"
用于 u"☺"
)。
我知道有些人可能会觉得这有争议。
【讨论】:
【参考方案2】:值得向那些不熟悉 __unicode__
函数的人指出 Python 2.x 中围绕它的一些默认行为,尤其是在与 __str__
一起定义时。
class A :
def __init__(self) :
self.x = 123
self.y = 23.3
#def __str__(self) :
# return "STR ".format( self.x , self.y)
def __unicode__(self) :
return u"UNICODE ".format( self.x , self.y)
a1 = A()
a2 = A()
print( "__repr__ checks")
print( a1 )
print( a2 )
print( "\n__str__ vs __unicode__ checks")
print( str( a1 ))
print( unicode(a1))
print( "".format( a1 ))
print( u"".format( a1 ))
产生以下控制台输出...
__repr__ checks
<__main__.A instance at 0x103f063f8>
<__main__.A instance at 0x103f06440>
__str__ vs __unicode__ checks
<__main__.A instance at 0x103f063f8>
UNICODE 123 23.3
<__main__.A instance at 0x103f063f8>
UNICODE 123 23.3
现在,当我取消注释 __str__
方法时
__repr__ checks
STR 123 23.3
STR 123 23.3
__str__ vs __unicode__ checks
STR 123 23.3
UNICODE 123 23.3
STR 123 23.3
UNICODE 123 23.3
【讨论】:
【参考方案3】:如果你在 Django 中同时使用 python2 和 python3,我推荐使用 python_2_unicode_compatible 装饰器:
Django 提供了一种简单的方法来定义适用于 Python 2 和 3 的 str() 和 unicode() 方法:您必须定义一个 str() 方法返回文本并应用 python_2_unicode_compatible() 装饰器。
正如前面 cmets 对另一个答案所指出的,future.utils 的某些版本也支持这个装饰器。在我的系统上,我需要为 python2 安装一个更新的 future 模块并为 python3 安装 future。之后,这里是一个功能示例:
#! /usr/bin/env python
from future.utils import python_2_unicode_compatible
from sys import version_info
@python_2_unicode_compatible
class SomeClass():
def __str__(self):
return "Called __str__"
if __name__ == "__main__":
some_inst = SomeClass()
print(some_inst)
if (version_info > (3,0)):
print("Python 3 does not support unicode()")
else:
print(unicode(some_inst))
这是示例输出(其中 venv2/venv3 是 virtualenv 实例):
~/tmp$ ./venv3/bin/python3 demo_python_2_unicode_compatible.py
Called __str__
Python 3 does not support unicode()
~/tmp$ ./venv2/bin/python2 demo_python_2_unicode_compatible.py
Called __str__
Called __str__
【讨论】:
【参考方案4】:__str__()
是旧方法——它返回字节。 __unicode__()
是新的首选方法——它返回字符。这些名称有点令人困惑,但在 2.x 中,出于兼容性原因,我们坚持使用它们。一般来说,你应该把你所有的字符串格式放在__unicode__()
,并创建一个存根__str__()
方法:
def __str__(self):
return unicode(self).encode('utf-8')
在 3.0 中,str
包含字符,因此将相同的方法命名为 __bytes__()
和 __str__()
。这些行为符合预期。
【讨论】:
你的意思是同时创建 unicode 和 str 方法,或者只是将字符串保留在 _(u"") 中并创建 string(没有 unicode 方法)? 只实现其中一个有什么陷阱吗?当你只实现__unicode__
然后执行str(obj)
会发生什么?
unicode
在 Python 3 上引发 NameError
,是一种适用于 2 和 3 的简单模式吗?
@bradley.ayers future
包还提供了python_2_unicode_compatible
,而没有 Django 作为依赖项。
视情况而定。因为 python3 不使用 unicode 而是 str ;) 用于 python 2 unicode【参考方案5】:
如果我不特别关心给定类的微优化字符串化,我总是只实现__unicode__
,因为它更通用。当我确实关心这种微小的性能问题(这是例外,而不是规则)时,只有__str__
(当我可以证明字符串化输出中永远不会有非 ASCII 字符时)或两者都有(当两者都可能时),可能会有所帮助。
我认为这些是可靠的原则,但在实践中很常见的是知道除了 ASCII 字符之外什么都没有,而无需努力证明它(例如,字符串化的形式只有数字、标点符号,也许还有一个简短的 ASCII 名称;- )在这种情况下,直接转向“just __str__
”方法是很典型的(但如果我与之合作的一个编程团队提出了一个本地指南来避免这种情况,我会对该提案+1,因为它很容易在这些问题上犯错并且“过早的优化是编程中万恶之源”;-)。
【讨论】:
在 python 2.6.2 中,我最近被绊倒了,因为特定的内置异常子类的实例使用 str(e) 和 unicode(e) 给出了不同的结果。 str(e) 提供用户友好的输出; unicode(e) 给出了不同的、用户不友好的输出。这被认为是错误的行为吗?类是 UnicodeDecodeError;为了避免混淆,我没有预先命名它——异常与 unicode 相关的事实并不是特别相关。【参考方案6】:随着世界变得越来越小,您遇到的任何字符串都有可能最终包含 Unicode。所以对于任何新的应用程序,你至少应该提供__unicode__()
。是否也覆盖 __str__()
只是个人喜好问题。
【讨论】:
如果您正在编写 Python 3 代码,则定义__unicode__
没有任何作用。以上是关于Python __str__ 与 __unicode__的主要内容,如果未能解决你的问题,请参考以下文章
django模型中的__str__()方法和__unicode__()方法
关于django模型里面的__str__和__unicode
使用from __future__ import unicode_literals
对模型使用自定义方法而不是 __unicode__/__str__?