Python __str__ versus __unicode__

213

Apakah ada konvensi python ketika Anda harus mengimplementasikan __str__()versus __unicode__(). Saya telah melihat kelas menimpa __unicode__()lebih sering daripada __str__()tetapi tampaknya tidak konsisten. Apakah ada aturan khusus ketika lebih baik menerapkan satu versus yang lain? Apakah perlu / praktik yang baik untuk mengimplementasikan keduanya?

Cory
sumber

Jawaban:

257

__str__()adalah metode lama - ia mengembalikan byte. __unicode__()adalah metode baru dan lebih disukai - ia mengembalikan karakter. Nama-nama agak membingungkan, tetapi dalam 2.x kita terjebak dengan mereka untuk alasan kompatibilitas. Secara umum, Anda harus meletakkan semua pemformatan string Anda __unicode__(), dan membuat __str__()metode rintisan :

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

Di 3.0, strberisi karakter, sehingga metode yang sama dinamai __bytes__()dan __str__(). Ini berperilaku seperti yang diharapkan.

John Millikin
sumber
2
Apakah maksud Anda membuat metode unicode dan str atau hanya menyimpan string di _ (u "") dan membuat string (tanpa metode unicode)?
muntu
12
Apakah ada kesulitan dalam mengimplementasikan hanya satu dari mereka? Apa yang terjadi ketika Anda hanya mengimplementasikan __unicode__dan kemudian melakukannya str(obj)?
RickyA
9
unicodemenimbulkan NameErrorpada Python 3, apakah pola sederhana yang bekerja di kedua 2 dan 3?
bradley.ayers
1
@ bradley.ayers futurepaket ini juga menyediakan python_2_unicode_compatibletanpa harus Django sebagai ketergantungan.
Monkpit
1
Tergantung. Karena python3 tidak menggunakan unicode melainkan str ;) untuk python 2 unicode
Eddwin Paz
23

Jika saya tidak terlalu peduli tentang pengoptimalan pengoptimalan mikro untuk kelas tertentu, saya akan selalu menerapkannya __unicode__saja, karena ini lebih umum. Ketika saya peduli tentang masalah kinerja menit seperti itu (yang merupakan pengecualian, bukan aturan), memiliki__str__ hanya (ketika saya bisa membuktikan tidak akan ada karakter non-ASCII dalam output yang dirangkai) atau keduanya (jika keduanya mungkin), mungkin Tolong.

Ini menurut saya adalah prinsip yang kuat, tetapi dalam praktiknya sangat umum TAHU tidak akan ada apa-apa selain karakter ASCII tanpa melakukan upaya untuk membuktikannya (mis. Formulir yang dikurifikasi hanya memiliki angka, tanda baca, dan mungkin nama ASCII pendek ;-) di mana Kasus itu cukup khas untuk pindah langsung ke pendekatan "adil __str__" (tetapi jika tim pemrograman saya bekerja dengan mengusulkan pedoman lokal untuk menghindari itu, saya akan menjadi +1 pada proposal, karena mudah salah dalam hal ini DAN "optimisasi prematur adalah akar dari semua kejahatan dalam pemrograman" ;-).

Alex Martelli
sumber
2
Dalam python 2.6.2, saya baru-baru ini tersandung karena contoh subkelas Exception bawaan yang khusus memberikan hasil yang berbeda dengan str (e) dan unicode (e). str (e) memberikan output yang mudah digunakan; unicode (e) memberikan output yang berbeda, tidak ramah pengguna. Apakah ini dianggap perilaku buggy? Kelasnya adalah UnicodeDecodeError; Saya tidak menyebutkannya di muka untuk menghindari kebingungan - fakta bahwa pengecualian tersebut terkait dengan unicode tidak terlalu relevan.
Paul Du Bois
13

Dengan dunia semakin kecil, kemungkinan bahwa setiap string yang Anda temui akan mengandung Unicode pada akhirnya. Jadi untuk semua aplikasi baru, Anda setidaknya harus menyediakan __unicode__(). Apakah Anda juga menimpa __str__()itu hanya masalah selera.

Aaron Digulla
sumber
8

Jika Anda bekerja di python2 dan python3 di Django, saya sarankan dekorator yang kompatibel python_2_unicode_compatible:

Django menyediakan cara sederhana untuk mendefinisikan metode str () dan unicode () yang bekerja pada Python 2 dan 3: Anda harus mendefinisikan metode str () yang mengembalikan teks dan menerapkan dekorator python_2_unicode_compatibleable ().

Seperti disebutkan dalam komentar sebelumnya untuk jawaban lain, beberapa versi future.utils juga mendukung dekorator ini. Di sistem saya, saya perlu menginstal modul masa depan yang lebih baru untuk python2 dan menginstal masa depan untuk python3. Setelah itu, maka berikut adalah contoh fungsionalnya:

#! /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))

Berikut adalah contoh output (di mana venv2 / venv3 adalah instance 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__
Sage
sumber
3

Python 2: Implementasikan __str __ () saja, dan kembalikan unicode.

Ketika __unicode__()dihilangkan dan seseorang memanggil unicode(o)atau u"%s"%o, Python memanggil o.__str__()dan mengkonversi ke unicode menggunakan pengkodean sistem. (Lihat dokumentasi__unicode__() .)

Yang sebaliknya tidak benar. Jika Anda menerapkan __unicode__()tetapi tidak __str__(), maka ketika seseorang memanggil str(o)atau "%s"%o, Python kembali repr(o).


Alasan

Mengapa akan berhasil mengembalikan unicodedari __str__()?
Jika __str__()mengembalikan unicode, Python secara otomatis mengubahnya menjadi strmenggunakan sistem pengkodean.

Apa untungnya?
① Ini membebaskan Anda dari khawatir tentang apa pengkodean sistem itu (yaitu, locale.getpreferredencoeding(…)). Tidak hanya berantakan, secara pribadi, tapi saya pikir itu adalah sesuatu yang harus dijaga sistem. ② Jika Anda berhati-hati, kode Anda mungkin keluar kompatibel dengan Python 3, di mana __str__()mengembalikan unicode.

Bukankah menipu untuk mengembalikan unicode dari fungsi yang disebut __str__()?
Sedikit. Namun, Anda mungkin sudah melakukannya. Jika Anda memiliki from __future__ import unicode_literalsdi bagian atas file Anda, ada kemungkinan besar Anda mengembalikan unicode tanpa menyadarinya.

Bagaimana dengan Python 3?
Python 3 tidak digunakan __unicode__(). Namun, jika Anda menerapkannya __str__()sehingga mengembalikan unicode di bawah Python 2 atau Python 3, maka bagian dari kode Anda akan kompatibel lintas.

Bagaimana jika saya ingin unicode(o)berbeda secara substansial str()?
Terapkan baik __str__()(mungkin kembali str) dan __unicode__(). Saya membayangkan ini akan jarang terjadi, tetapi Anda mungkin ingin keluaran yang berbeda secara substansial (misalnya, versi ASCII karakter khusus, seperti ":)"untuk u"☺").

Saya menyadari beberapa orang mungkin menemukan ini kontroversial.

Alex Quinn
sumber
1

Ada baiknya menunjukkan kepada mereka yang tidak terbiasa dengan __unicode__fungsi beberapa perilaku default yang mengelilinginya kembali di Python 2.x, terutama ketika didefinisikan berdampingan dengan __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 ))

menghasilkan output konsol berikut ...

__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

Sekarang ketika saya batalkan komentar __str__metode

__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
jxramos
sumber