Python __str__ проти __unicode__


213

Чи існує умова python для того, коли слід реалізувати __str__()проти __unicode__(). Я бачив заняття, які переосмислюють __unicode__()частіше, __str__()але, схоже, це не є послідовним. Чи є конкретні правила, коли краще реалізувати одне проти іншого? Чи потрібно / хороша практика для впровадження обох?

Відповіді:


257

__str__()це старий метод - він повертає байти. __unicode__()це новий, бажаний метод - він повертає символів. Назви трохи заплутані, але в 2.x ми з ними тримаємось з міркувань сумісності. Як правило, слід вкласти все форматування рядків __unicode__()і створити __str__()метод заглушки :

def __str__(self):
    return unicode(self).encode('utf-8')

В 3.0 strміститься символи, тому такі самі методи називаються __bytes__()і __str__(). Вони поводяться так, як очікувалося.


2
Ви маєте на увазі створення методів unicode та str або просто зберігати рядки в _ (u "") та створювати рядок (без методу unicode)?
muntu

12
Чи є якась помилка в реалізації лише однієї з них? Що відбувається, коли ти лише реалізуєш __unicode__і потім зробиш str(obj)?
RickyA

9
unicodeпіднімає a NameErrorна Python 3, це проста модель, яка працює в обох 2 і 3?
bradley.ayers

1
@ bradley.ayers futureпакет також надає, python_2_unicode_compatibleне маючи Джанго як залежність.
Monkpit

1
Це залежить. Оскільки python3 не використовує unicode, а натомість str ;) для python 2 unicode
Eddwin Paz

23

Якщо я не особливо хвилювався мікро-оптимізацією строфікації для даного класу, я завжди реалізовував би __unicode__лише це, оскільки це більш загальне. Коли мені важливі такі хвилинні проблеми з продуктивністю (що є винятком, а не правилом), маючи __str__лише (коли я можу довести, що ніколи не буде символів, що не належать до ASCII, в раціоналізованому виході) або обох (коли можливі обидва). допомогу.

Це, на мою думку, є твердими принципами, але на практиці це дуже часто ЗНАЄТЬСЯ, якщо символи ASCII не будуть робити нічого, не докладаючи зусиль, щоб довести це (наприклад, у строфікованій формі є лише цифри, пунктуація та, можливо, коротке ім'я ASCII ;-) в якому У випадку цілком типово переходити безпосередньо до "справедливого __str__" підходу (але якщо команда програмування, з якою я працював, запропонувала місцевий настанов, щоб уникнути цього, я ставлю +1 до пропозиції, оскільки в цих питаннях легко помилитися І "передчасна оптимізація - корінь усього зла в програмуванні" ;-).


2
У python 2.6.2 я нещодавно зіткнувся, оскільки екземпляри певного вкладеного підкласу Exception давали різні результати з str (e) та unicode (e). str (e) дав дружній для користувача вихід; unicode (e) давав різні, непривітні для користувача виводи. Чи вважається це поведінка баггі? Клас - UnicodeDecodeError; Я не назвав його наперед, щоб уникнути плутанини - той факт, що виняток пов'язаний з unicode, не особливо актуальний.
Пол Дю Буа

13

Коли світ стає меншим, велика ймовірність, що будь-яка рядок, з яким ви зіткнетеся, з часом містить Unicode. Тому для будь-яких нових додатків вам слід принаймні надати __unicode__(). Чи ви теж перекриєте, __str__()це лише питання смаку.


8

Якщо ви працюєте як в python2, так і в python3 в Django, я рекомендую декоратор, сумісний із python_2_unicode_:

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__

3

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__()повертається unicode.

Чи не оманливо повертати унікод з функції, що називається __str__()?
Трішки. Однак ви, можливо, це вже робите. Якщо у вас є from __future__ import unicode_literalsу верхній частині файлу, є хороший шанс повернути unicode, навіть не підозрюючи про це.

Що з Python 3?
Python 3 не використовує __unicode__(). Однак якщо ви реалізуєте __str__()так, що він повертає unicode під будь-яким Python 2 або Python 3, то ця частина вашого коду буде сумісною.

Що робити, якщо я хочу unicode(o)істотно відрізнятися від str()?
Виконайте як __str__()(можливо повернення str), так і __unicode__(). Я думаю, що це буде рідко, але ви, можливо, захочете істотно іншого виводу (наприклад, ASCII версії спеціальних символів, як ":)"для u"☺").

Я усвідомлюю, що деякі можуть вважати це спірним.


1

Варто вказати тим, хто не знайомий з __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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.