Python __str__ против __unicode__
Существует ли соглашение python, когда вы должны реализовать __str__()
по сравнению с __unicode__()
. Я видел, что классы переопределяют __unicode__()
чаще, чем __str__()
, но, похоже, не соответствуют друг другу. Существуют ли конкретные правила, когда лучше реализовать один против другого? Нужно ли/хорошая практика реализовать оба?
Ответы
Ответ 1
__str__()
- это старый метод - он возвращает байты. __unicode__()
- новый, предпочтительный метод - он возвращает символы. Имена немного запутаны, но в 2.x мы застряли с ними по соображениям совместимости. Как правило, вы должны поместить все форматирование строк в __unicode__()
и создать метод stub __str__()
:
def __str__(self):
return unicode(self).encode('utf-8')
В 3.0, str
содержит символы, поэтому те же методы называются __bytes__()
и __str__()
. Они ведут себя так, как ожидалось.
Ответ 2
Если бы я не особо заботился об оптимизации микрооптимизации для данного класса, я бы всегда реализовал только __unicode__
, поскольку он более общий. Когда меня волнуют такие мелкие проблемы с производительностью (это исключение, а не правило), имея только __str__
(когда я могу доказать, что в строковом выходе никогда не будет символов без символов ASCII) или обоих (когда оба возможны), может помочь.
Я думаю, что это солидные принципы, но на практике это очень распространено для KNOW, не будет ничего, кроме символов ASCII, не прилагая усилий, чтобы доказать это (например, стробированная форма имеет только цифры, знаки препинания и, возможно, короткое имя ASCII;), и в этом случае вполне типично перейти непосредственно к подходу "just __str__
" (но если команда программирования, с которой я работал, предложила местное руководство, чтобы избежать этого, я бы добавил +1 к предложению, так как это легко ошибиться в этих вопросах И "преждевременная оптимизация - корень всего зла в программировании"; -).
Ответ 3
Когда мир становится все меньше, есть вероятность, что любая строка, с которой вы столкнулись, в конечном итоге будет содержать Unicode. Поэтому для любых новых приложений вы должны хотя бы предоставить __unicode__()
. Если вы также переопределяете __str__()
, тогда это просто вопрос вкуса.
Ответ 4
Если вы работаете в python2 и python3 в Django, я рекомендую python_2_unicode_compatible decorator:
Django предоставляет простой способ определения str() и unicode() методов, которые работают на Python 2 и 3: вы должны определить str() возвращающий текст и применение декоратора python_2_unicode_compatible().
Как отмечалось в предыдущих комментариях к другому ответу, некоторые версии future.utils также поддерживают этот декоратор. В моей системе мне нужно было установить новый будущий модуль для python2 и установить будущее для python3. После этого здесь приведен пример:
#! /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 - виртуальные экземпляры):
~/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__
Ответ 5
__unicode__
кто не знаком с функцией __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
Ответ 6
Python 2: Реализуйте только __str __() и возвращайте юникод.
Когда __unicode__()
опущен и кто-то вызывает unicode(o)
или u"%s"%o
, Python вызывает o.__str__()
и конвертирует в unicode с использованием системной кодировки. (См. Документацию __unicode__()
.)
Обратное не верно. Если вы реализуете __unicode__()
но не __str__()
, то когда кто-то вызывает str(o)
или "%s"%o
, Python возвращает repr(o)
.
обоснование
Почему бы работать, чтобы вернуть unicode
из __str__()
?
Если __str__()
возвращает юникод, Python автоматически преобразует его в str
с использованием системной кодировки.
Какая выгода?
① Это освобождает вас от беспокойства о том, что такое системная кодировка (то есть locale.getpreferredencoeding(…)
). Лично это не только грязно, но я думаю, что система все равно должна позаботиться о ней. ② Если вы осторожны, ваш код может оказаться кросс-совместимым с Python 3, в котором __str__()
возвращает юникод.
Разве не обманчиво возвращать юникод из функции с именем __str__()
?
Немного. Тем не менее, вы, возможно, уже делаете это. Если у вас есть from __future__ import unicode_literals
вверху файла, есть большая вероятность, что вы from __future__ import unicode_literals
юникод, даже не зная об этом.
А как насчет Python 3?
Python 3 не использует __unicode__()
. Однако если вы реализуете __str__()
чтобы он возвращал юникод в Python 2 или Python 3, то эта часть вашего кода будет кросс-совместимой.
Что если я хочу, чтобы unicode(o)
существенно отличался от str()
?
__str__()
оба __str__()
(возможно, возвращая str
) и __unicode__()
. Я предполагаю, что это было бы редко, но вы могли бы хотеть существенно различного вывода (например, ASCII-версии специальных символов, таких как ":)"
для u"☺"
).
Я понимаю, что некоторые могут найти это спорным.