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"☺").

Я понимаю, что некоторые могут найти это спорным.