Perbedaan antara __str__ dan __repr__?

Jawaban:

2724

Alex merangkum dengan baik tetapi, yang mengejutkan, terlalu ringkas.

Pertama, izinkan saya mengulangi poin utama dalam posting Alex :

  • Implementasi default tidak berguna (sulit untuk memikirkan yang tidak akan, tapi ya)
  • __repr__ tujuannya adalah untuk tidak ambigu
  • __str__ tujuannya adalah agar dapat dibaca
  • Wadah ini __str__menggunakan terkandung benda__repr__

Implementasi default tidak berguna

Ini sebagian besar mengejutkan karena standar Python cenderung cukup berguna. Namun, dalam hal ini, memiliki default __repr__yang akan bertindak seperti:

return "%s(%r)" % (self.__class__, self.__dict__)

akan terlalu berbahaya (misalnya, terlalu mudah untuk masuk ke rekursi tak terbatas jika benda saling referensi). Jadi Python keluar. Perhatikan bahwa ada satu default yang benar: jika __repr__didefinisikan, dan __str__tidak, objek akan berperilaku seolah-olah __str__=__repr__.

Ini berarti, secara sederhana: hampir setiap objek yang Anda implementasikan harus memiliki fungsional __repr__yang dapat digunakan untuk memahami objek. Penerapan __str__adalah opsional: lakukan itu jika Anda memerlukan fungsionalitas "cetak cantik" (misalnya, digunakan oleh pembuat laporan).

Tujuannya __repr__adalah untuk tidak ambigu

Biarkan saya keluar dan mengatakannya - saya tidak percaya pada para penentang. Saya tidak benar-benar tahu cara menggunakan debugger apa pun, dan belum pernah menggunakannya secara serius. Lebih jauh lagi, saya percaya bahwa kesalahan besar dalam debugger adalah sifat dasar mereka - kebanyakan kegagalan yang saya debug terjadi sejak lama, di galaksi yang sangat jauh. Ini berarti bahwa saya benar-benar percaya, dengan semangat keagamaan, dalam penebangan. Logging adalah sumber kehidupan dari sistem server fire-and-forget yang layak. Python membuatnya mudah untuk login: dengan mungkin beberapa pembungkus khusus proyek, yang Anda butuhkan hanyalah a

log(INFO, "I am in the weird function and a is", a, "and b is", b, "but I got a null C — using default", default_c)

Tetapi Anda harus melakukan langkah terakhir - pastikan setiap objek yang Anda implementasikan memiliki repr yang berguna, jadi kode seperti itu bisa berfungsi. Inilah sebabnya mengapa "eval" muncul: jika Anda memiliki informasi yang cukup eval(repr(c))==c, itu berarti Anda tahu semua yang perlu diketahui c. Jika itu cukup mudah, setidaknya dengan cara yang kabur, lakukanlah. Jika tidak, pastikan Anda memiliki informasi yang cukup tentang hal citu. Saya biasanya menggunakan format seperti eval:"MyClass(this=%r,that=%r)" % (self.this,self.that) . Itu tidak berarti bahwa Anda benar-benar dapat membangun MyClass, atau bahwa itu adalah argumen konstruktor yang tepat - tetapi itu adalah bentuk yang berguna untuk menyatakan "ini adalah semua yang perlu Anda ketahui tentang instance ini".

Catatan: Saya menggunakan di %ratas, tidak %s. Anda selalu ingin menggunakan repr()[atau %rmemformat karakter, setara] di dalam __repr__implementasi, atau Anda mengalahkan tujuan repr. Anda ingin dapat membedakan MyClass(3)dan MyClass("3").

Tujuannya __str__agar dapat dibaca

Secara khusus, ini tidak dimaksudkan untuk tidak ambigu - perhatikan itu str(3)==str("3"). Demikian juga, jika Anda menerapkan abstraksi IP, memiliki str itu terlihat seperti 192.168.1.1 baik-baik saja. Ketika menerapkan abstraksi tanggal / waktu, str dapat berupa "2010/4/12 15:35:22", dll. Tujuannya adalah untuk mewakilinya dengan cara yang ingin dibaca oleh pengguna, bukan programmer. Memotong angka yang tidak berguna, berpura-pura menjadi kelas lain - selama itu mendukung keterbacaan, itu adalah peningkatan.

Wadah ini __str__menggunakan terkandung benda__repr__

Ini sepertinya mengejutkan, bukan? Ini sedikit, tetapi seberapa mudah dibaca jika digunakan __str__?

[moshe is, 3, hello
world, this is a list, oh I don't know, containing just 4 elements]

Tidak terlalu. Secara khusus, string dalam wadah akan merasa terlalu mudah untuk mengganggu representasi string-nya. Dalam menghadapi ambiguitas, ingatlah, Python menolak godaan untuk menebak. Jika Anda ingin perilaku di atas saat Anda mencetak daftar, cukup

print "[" + ", ".join(l) + "]"

(Anda mungkin juga bisa mencari tahu apa yang harus dilakukan tentang kamus.

Ringkasan

Terapkan __repr__untuk kelas yang Anda laksanakan. Ini harus menjadi sifat kedua. Terapkan __str__jika Anda pikir akan bermanfaat untuk memiliki versi string yang salah di sisi keterbacaan.

moshez
sumber
154
Jelas tidak setuju dengan pendapat Anda bahwa debugging bukan cara yang tepat. Untuk pengembangan gunakan debugger (dan / atau logging), untuk logging penggunaan produksi. Dengan debugger Anda memiliki pandangan tentang segala sesuatu yang salah ketika masalah terjadi. Anda dapat melihat gambar lengkapnya. Kecuali Anda login SEMUA, Anda tidak bisa mendapatkannya. Ditambah lagi jika Anda masuk semua yang Anda harus menyeberang melalui banyak data untuk mendapatkan apa yang Anda inginkan.
Samuel
21
Jawaban yang bagus (kecuali sedikit tentang tidak menggunakan debugger). Saya hanya ingin menambahkan tautan ke T&J lain ini tentang str vs unicode di Python 3 yang dapat relevan dengan diskusi untuk orang-orang yang telah beralih.
ThatAintWorking
11
plus1 untuk debuggers tidak berguna, dan jangan mengukur sepeser pun. Dapatkan throughput logging Anda sebagai gantinya. Dan ya ini posting yang ditulis dengan baik. Ternyata __repr__itulah yang saya butuhkan untuk debugging. Terima kasih untuk bantuannya.
personal_cloud
7
Terlepas dari kebodohan debugger Anda, saya mempelajari% r dan itu layak untuk dipilih
Mickey Perlstein
7
pada debugger vs tanpa debugger: jangan mendapatkan pendapat yang sudah mengakar. Dalam beberapa aplikasi, debugging tidak realistis, biasanya ketika real-time terlibat, atau ketika kode Anda hanya dijalankan dari jarak jauh pada platform dengan sedikit akses atau tanpa konsol. Dalam kebanyakan kasus lain, akan lebih cepat untuk berhenti pada pengecualian untuk menyelidiki, atau untuk menetapkan breakpoint, karena Anda tidak harus melalui ribuan baris logging (yang akan mengacaukan disk Anda dan memperlambat aplikasi). Akhirnya, tidak selalu mungkin untuk masuk, misalnya pada perangkat yang disematkan, ada debugger juga teman Anda.
RedGlyph
523

Aturan praktis saya: __repr__untuk pengembang, __str__untuk pelanggan.

Ned Batchelder
sumber
2
Ini benar karena untuk obj = uuid.uuid1 (), obj .__ str __ () adalah "2d7fc7f0-7706-11e9-94ae-0242ac110002" dan obj .__ repr __ () adalah "UUID ('2d7fc7f0-7706-11e9-94ae-0242ac110002 ') ". Pengembang membutuhkan (nilai + asal) sedangkan pelanggan membutuhkan nilai dan mereka tidak peduli bagaimana mereka mendapatkannya!
Naren Yellavula
1
Di sini pelanggan tidak harus berarti pengguna akhir. Ini adalah klien atau pengguna objek. Jadi jika ini adalah SDK maka pengembang SDK akan menggunakan __str__sehingga pengembang normal memiliki objek yang dapat dibaca. Di sisi lain, __repr__adalah untuk para pengembang SDK sendiri.
Shiplu Mokaddim
398

Kecuali Anda secara khusus bertindak untuk memastikan sebaliknya, sebagian besar kelas tidak memiliki hasil yang bermanfaat untuk:

>>> class Sic(object): pass
... 
>>> print str(Sic())
<__main__.Sic object at 0x8b7d0>
>>> print repr(Sic())
<__main__.Sic object at 0x8b7d0>
>>> 

Seperti yang Anda lihat - tidak ada perbedaan, dan tidak ada info di luar kelas dan objek id. Jika Anda hanya mengganti satu dari dua ...:

>>> class Sic(object): 
...   def __repr__(object): return 'foo'
... 
>>> print str(Sic())
foo
>>> print repr(Sic())
foo
>>> class Sic(object):
...   def __str__(object): return 'foo'
... 
>>> print str(Sic())
foo
>>> print repr(Sic())
<__main__.Sic object at 0x2617f0>
>>> 

seperti yang Anda lihat, jika Anda menimpa __repr__, itu JUGA digunakan untuk __str__, tetapi tidak sebaliknya.

Informasi penting lainnya yang perlu diketahui: __str__pada wadah bawaan menggunakan__repr__ , BUKAN __str__, untuk item yang dikandungnya. Dan, terlepas dari kata-kata pada subjek yang ditemukan dalam dokumen biasa, hampir tidak ada orang yang mengganggu membuat __repr__objek menjadi string yang evaldapat digunakan untuk membangun objek yang sama (itu terlalu sulit, DAN tidak tahu bagaimana modul yang relevan sebenarnya diimpor membuatnya benar-benar tidak mungkin keluar).

Jadi, saran saya: fokuslah untuk membuat yang __str__dapat dibaca manusia, dan __repr__sejelas mungkin, bahkan jika itu mengganggu tujuan tidak jelas yang tidak dapat dicapai untuk membuat __repr__nilai yang dikembalikan dapat diterima sebagai masukan untuk __eval__!

Alex Martelli
sumber
34
Dalam pengujian unit saya, saya selalu memeriksa yang eval(repr(foo))mengevaluasi ke objek yang sama dengan foo. Anda benar bahwa itu tidak akan berfungsi di luar kasus pengujian saya karena saya tidak tahu bagaimana modul diimpor, tetapi ini setidaknya memastikan bahwa itu berfungsi dalam beberapa konteks yang dapat diprediksi. Saya pikir ini cara yang baik untuk mengevaluasi jika hasilnya __repr__cukup eksplisit. Melakukan ini dalam unit test juga membantu memastikan bahwa __repr__perubahan berikut mengikuti kelas.
Steven T. Snyder
4
Saya selalu berusaha memastikan bahwa eval(repr(spam)) == spam(setidaknya dalam konteks yang tepat), atau eval(repr(spam))memunculkan a SyntaxError. Dengan begitu Anda menghindari kebingungan. (Dan itu hampir benar untuk builtin dan sebagian besar stdlib, kecuali untuk, misalnya, daftar rekursif, di mana a=[]; a.append(a); print(eval(repr(a)))memberi Anda [[Ellipses]]...) Tentu saja saya tidak melakukan itu untuk benar-benar digunakan eval(repr(spam)) , kecuali sebagai pemeriksaan kewarasan dalam unit test ... tapi saya lakukan terkadang salin dan tempel repr(spam)ke sesi interaktif.
abarnert
Mengapa wadah (daftar, tuple) tidak digunakan __str__untuk setiap elemen, bukan __repr__? Tampak jelas salah bagi saya, karena saya menerapkan yang dapat dibaca __str__di objek saya dan ketika itu adalah bagian dari daftar saya melihat yang lebih buruk __repr__sebagai gantinya.
SuperGeo
Hanya mengalami bug menjengkelkan terkait dengan fakta yang eval(repr(x))gagal bahkan untuk tipe bawaan: class A(str, Enum): X = 'x'akan meningkatkan SyntaxError eval(repr(A.X)). Sedih, tapi bisa dimengerti. BTW, eval(str(A.X))sebenarnya berfungsi, tetapi tentu saja hanya jika class Adalam ruang lingkup - jadi mungkin tidak terlalu berguna.
Maks
@SuperGeo Jawaban lain mencakup ini: strelemen penggunaan wadah reprkarena [1, 2, 3]! = ["1", "2, 3"].
mtraceur
163

__repr__: representasi objek python biasanya eval akan mengubahnya kembali ke objek itu

__str__: adalah apa pun yang Anda pikirkan adalah objek itu dalam bentuk teks

misalnya

>>> s="""w'o"w"""
>>> repr(s)
'\'w\\\'o"w\''
>>> str(s)
'w\'o"w'
>>> eval(str(s))==s
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1
    w'o"w
       ^
SyntaxError: EOL while scanning single-quoted string
>>> eval(repr(s))==s
True
Andrew Clark
sumber
151

Singkatnya, tujuannya __repr__adalah untuk tidak ambigu dan __str__dapat dibaca.

Ini adalah contoh yang bagus:

>>> import datetime
>>> today = datetime.datetime.now()
>>> str(today)
'2012-03-14 09:21:58.130922'
>>> repr(today)
'datetime.datetime(2012, 3, 14, 9, 21, 58, 130922)'

Baca dokumentasi ini untuk repr:

repr(object)

Mengembalikan string yang berisi representasi objek yang dapat dicetak. Ini adalah nilai yang sama yang dihasilkan oleh konversi (kutip terbalik). Terkadang berguna untuk dapat mengakses operasi ini sebagai fungsi biasa. Untuk banyak jenis, fungsi ini berusaha untuk mengembalikan string yang akan menghasilkan objek dengan nilai yang sama ketika diteruskan ke eval(), jika representasi adalah string yang terlampir dalam kurung sudut yang berisi nama jenis objek bersama dengan informasi tambahan sering termasuk nama dan alamat objek. Kelas dapat mengontrol apa fungsi ini dikembalikan untuk instance-nya dengan mendefinisikan __repr__()metode.

Berikut ini adalah dokumentasi untuk str:

str(object='')

Mengembalikan string yang berisi representasi objek yang dapat dicetak dengan baik. Untuk string, ini mengembalikan string itu sendiri. Perbedaannya repr(object)adalah bahwa str(object)tidak selalu berusaha untuk mengembalikan string yang dapat diterima eval(); tujuannya adalah mengembalikan string yang dapat dicetak. Jika tidak ada argumen yang diberikan, mengembalikan string kosong '',.

bitoffdev
sumber
1
Apa arti dari string yang dapat dicetak di sini? Bisakah Anda jelaskan?
Vicrobot
115

Apa perbedaan antara __str__dan __repr__dalam Python?

__str__ (dibaca sebagai "string dunder (double-underscore)") dan __repr__ (dibaca sebagai "dunder-repper" (untuk "representasi")) keduanya adalah metode khusus yang mengembalikan string berdasarkan keadaan objek.

__repr__menyediakan perilaku cadangan jika __str__tidak ada.

Jadi pertama-tama seseorang harus menulis sebuah __repr__yang memungkinkan Anda untuk mengembalikan objek setara dari string yang dikembalikannya misalnya menggunakan evalatau dengan mengetikkannya dalam karakter-untuk-karakter dalam shell Python.

Kapan saja nanti, seseorang dapat menulis __str__untuk representasi string yang dapat dibaca pengguna dari instance, ketika seseorang percaya itu perlu.

__str__

Jika Anda mencetak objek, atau meneruskannya ke format,, str.formatatau str, kemudian jika suatu __str__metode didefinisikan, metode itu akan dipanggil, jika tidak, __repr__akan digunakan.

__repr__

The __repr__metode ini disebut oleh fungsi builtin reprdan apa yang bergema di shell python Anda ketika mengevaluasi sebuah ekspresi yang mengembalikan sebuah objek.

Karena menyediakan cadangan untuk __str__, jika Anda hanya bisa menulis satu, mulailah dengan__repr__

Inilah bantuan bawaan pada repr:

repr(...)
    repr(object) -> string

    Return the canonical string representation of the object.
    For most object types, eval(repr(object)) == object.

Artinya, untuk sebagian besar objek, jika Anda mengetik apa yang dicetak oleh repr, Anda harus dapat membuat objek yang setara. Tapi ini bukan implementasi standar.

Implementasi Default dari __repr__

Objek default __repr__adalah ( sumber C Python ) sesuatu seperti:

def __repr__(self):
    return '<{0}.{1} object at {2}>'.format(
      self.__module__, type(self).__name__, hex(id(self)))

Itu berarti secara default Anda akan mencetak modul dari objek, nama kelas, dan representasi heksadesimal dari lokasinya dalam memori - misalnya:

<__main__.Foo object at 0x7f80665abdd0>

Informasi ini tidak terlalu berguna, tetapi tidak ada cara untuk mendapatkan bagaimana seseorang dapat secara akurat membuat representasi kanonik dari setiap contoh yang diberikan, dan itu lebih baik daripada tidak sama sekali, setidaknya memberi tahu kita bagaimana kita dapat secara unik mengidentifikasi itu dalam memori.

Bagaimana bisa __repr__bermanfaat?

Mari kita lihat betapa bergunanya itu, menggunakan shell Python dan datetimeobjek. Pertama-tama kita perlu mengimpor datetimemodul:

import datetime

Jika kita memanggil datetime.nowshell, kita akan melihat semua yang kita butuhkan untuk membuat ulang objek datetime yang setara. Ini dibuat oleh datetime __repr__:

>>> datetime.datetime.now()
datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)

Jika kita mencetak objek datetime, kita melihat format yang dapat dibaca manusia (sebenarnya, ISO). Ini diimplementasikan oleh datetime __str__:

>>> print(datetime.datetime.now())
2015-01-24 20:05:44.977951

Ini adalah masalah sederhana untuk membuat ulang objek yang hilang karena kami tidak menetapkannya ke variabel dengan menyalin dan menempel dari __repr__output, dan kemudian mencetaknya, dan kami mendapatkannya dalam output yang dapat dibaca manusia sama seperti objek lainnya:

>>> the_past = datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
>>> print(the_past)
2015-01-24 20:05:36.491180

Bagaimana cara menerapkannya?

Saat Anda berkembang, Anda mungkin ingin dapat mereproduksi objek dalam kondisi yang sama, jika memungkinkan. Ini, misalnya, adalah bagaimana mendefinisikan objek datetime __repr__( sumber Python ). Ini cukup rumit, karena semua atribut yang diperlukan untuk mereproduksi objek seperti itu:

def __repr__(self):
    """Convert to formal string, for repr()."""
    L = [self._year, self._month, self._day,  # These are never zero
         self._hour, self._minute, self._second, self._microsecond]
    if L[-1] == 0:
        del L[-1]
    if L[-1] == 0:
        del L[-1]
    s = "%s.%s(%s)" % (self.__class__.__module__,
                       self.__class__.__qualname__,
                       ", ".join(map(str, L)))
    if self._tzinfo is not None:
        assert s[-1:] == ")"
        s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
    if self._fold:
        assert s[-1:] == ")"
        s = s[:-1] + ", fold=1)"
    return s

Jika Anda ingin objek Anda memiliki representasi yang lebih dapat dibaca manusia, Anda dapat menerapkan __str__selanjutnya. Inilah cara mengimplementasikan objek datetime ( sumber Python ) __str__, yang mudah dilakukan karena ia memiliki fungsi untuk menampilkannya dalam format ISO:

def __str__(self):
    "Convert to string, for str()."
    return self.isoformat(sep=' ')

Setel __repr__ = __str__?

Ini adalah kritik terhadap jawaban lain di sini yang menyarankan pengaturan __repr__ = __str__.

Pengaturan __repr__ = __str__konyol - __repr__adalah fallback untuk __str__dan __repr__, ditulis untuk penggunaan pengembang dalam debugging, harus ditulis sebelum Anda menulis a__str__ .

Anda membutuhkan __str__ hanya ketika Anda membutuhkan representasi objek teks.

Kesimpulan

Tentukan __repr__objek yang Anda tulis sehingga Anda dan pengembang lainnya memiliki contoh yang dapat direproduksi saat menggunakannya saat Anda mengembangkan. Tentukan __str__kapan Anda membutuhkan representasi string yang dapat dibaca manusia.

Aaron Hall
sumber
Bukankah seharusnya sesuatu seperti itu type(obj).__qualname__?
Solomon Ucko
@SolomonUcko ya dalam Python 3, yang tampaknya menjadi kasus - Saya sudah memburu kode sumber di mana ini diterapkan dan saya akan memperbarui jawaban saya dengan informasi itu ketika saya mendapatkannya bersama.
Aaron Hall
33

Pada halaman 358 dari buku Python scripting untuk ilmu komputasi oleh Hans Petter Langtangen, itu jelas menyatakan bahwa

  • The __repr__Tujuan di representasi string lengkap objek;
  • The __str__adalah untuk mengembalikan string yang bagus untuk mencetak.

Jadi, saya lebih suka memahaminya sebagai

  • repr = mereproduksi
  • str = string (representasi)

dari sudut pandang pengguna meskipun ini adalah kesalahpahaman yang saya buat ketika belajar python.

Contoh kecil tapi bagus juga diberikan pada halaman yang sama sebagai berikut:

Contoh

In [38]: str('s')
Out[38]: 's'

In [39]: repr('s')
Out[39]: "'s'"

In [40]: eval(str('s'))
Traceback (most recent call last):

  File "<ipython-input-40-abd46c0c43e7>", line 1, in <module>
    eval(str('s'))

  File "<string>", line 1, in <module>

NameError: name 's' is not defined


In [41]: eval(repr('s'))
Out[41]: 's'
Yong Yang
sumber
Itu di hal. # 351
jiten
4
Agak menyesatkan untuk disebut reprsebagai mereproduksi. Lebih baik menganggapnya sebagai mewakili.
NelsonGon
31

Terlepas dari semua jawaban yang diberikan, saya ingin menambahkan beberapa poin: -

1) __repr__() dipanggil ketika Anda cukup menulis nama objek pada konsol python interaktif dan tekan enter.

2) __str__() dipanggil ketika Anda menggunakan objek dengan pernyataan cetak.

3) Dalam hal, jika __str__tidak ada, maka cetak dan fungsi apa pun yang menggunakan str()panggilan__repr__() .

4) __str__()wadah, ketika dipanggil akan menjalankan __repr__()metode elemen yang terkandung.

5) str()dipanggil ke dalam __str__()bisa berpotensi berulang tanpa kasus dasar, dan kesalahan pada kedalaman rekursi maksimum.

6) __repr__()dapat memanggil repr()yang akan berusaha untuk menghindari rekursi tak terbatas secara otomatis, menggantikan objek yang sudah diwakili ....

Mangu Singh Rajpurohit
sumber
14

Untuk membuatnya lebih sederhana:

__str__digunakan untuk menunjukkan representasi string objek Anda agar mudah dibaca oleh orang lain.

__repr__digunakan untuk menunjukkan representasi string dari para objek.

Katakanlah saya ingin membuat Fractionkelas di mana representasi string dari fraksi adalah '(1/2)' dan objek (kelas Fraksi) harus direpresentasikan sebagai 'Fraksi (1,2)'

Jadi kita bisa membuat kelas Fraksi sederhana:

class Fraction:
    def __init__(self, num, den):
        self.__num = num
        self.__den = den

    def __str__(self):
        return '(' + str(self.__num) + '/' + str(self.__den) + ')'

    def __repr__(self):
        return 'Fraction (' + str(self.__num) + ',' + str(self.__den) + ')'



f = Fraction(1,2)
print('I want to represent the Fraction STRING as ' + str(f)) # (1/2)
print('I want to represent the Fraction OBJECT as ', repr(f)) # Fraction (1,2)
Nol
sumber
13

Dalam semua kejujuran, eval(repr(obj))tidak pernah digunakan. Jika Anda menemukan diri Anda menggunakannya, Anda harus berhenti, karena evalberbahaya, dan string adalah cara yang sangat tidak efisien untuk membuat serialisasi objek Anda (gunakanpickle sebagai gantinya).

Karena itu, saya akan merekomendasikan pengaturan __repr__ = __str__. Alasannya adalah bahwa str(list)panggilan reprpada elemen (saya menganggap ini sebagai salah satu kelemahan desain terbesar dari Python yang tidak ditangani oleh Python 3). Hasil aktual reprmungkin tidak akan terlalu membantu sebagai hasil dari print [your, objects].

Untuk memenuhi syarat ini, dalam pengalaman saya, kasus penggunaan paling berguna dari reprfungsi ini adalah untuk meletakkan string di dalam string lain (menggunakan pemformatan string). Dengan cara ini, Anda tidak perlu khawatir lolos dari penawaran atau apa pun. Tetapi perhatikan bahwa tidak ada yang evalterjadi di sini.

penilai
sumber
19
Saya pikir ini melewatkan intinya. Penggunaan eval(repr(obj))adalah tes kewarasan dan aturan praktis - jika ini menciptakan kembali objek asli dengan benar maka Anda memiliki __repr__implementasi yang layak . Itu tidak dimaksudkan bahwa Anda benar-benar membuat cerita bersambung objek dengan cara ini.
jwg
7
evalsecara inheren tidak berbahaya. Apakah tidak lebih berbahaya daripada unlink, openatau menulis ke file. Haruskah kita berhenti menulis ke file karena mungkin serangan jahat dapat menggunakan jalur file sewenang-wenang untuk memasukkan konten ke dalamnya? Semuanya berbahaya jika digunakan secara bodoh oleh orang bodoh. Idiocy berbahaya. Efek Dunning-Kruger berbahaya. evalhanyalah sebuah fungsi.
Luis Masuelli
12

Dari Wiki Referensi Python (An Tidak Resmi) (salinan arsip) oleh effbot:

__str__" Menghitung representasi string" informal "dari sebuah objek. Ini berbeda dari __repr__yang tidak harus menjadi ekspresi Python yang valid: representasi yang lebih nyaman atau ringkas dapat digunakan sebagai gantinya. "

Casebash
sumber
3
__repr__sama sekali tidak diperlukan untuk mengembalikan ekspresi Python vaild.
Fisikawan Gila
10

str - Membuat objek string baru dari objek yang diberikan.

repr - Mengembalikan representasi string kanonik objek.

Perbedaan:

str ():

  • membuat objek dapat dibaca
  • menghasilkan output untuk pengguna akhir

repr ():

  • membutuhkan kode yang mereproduksi objek
  • menghasilkan output untuk pengembang
Inconnu
sumber
8

Satu aspek yang hilang dalam jawaban lain. Memang benar bahwa secara umum polanya adalah:

  • Tujuan dari __str__ : dapat dibaca manusia
  • Sasaran __repr__: tidak ambigu, mungkin dapat dibaca melalui mesineval

Sayangnya, diferensiasi ini cacat, karena Python REPL dan juga IPython digunakan __repr__untuk mencetak objek dalam konsol REPL (lihat pertanyaan terkait untuk Python dan IPython ). Dengan demikian, proyek yang ditargetkan untuk pekerjaan konsol interaktif (misalnya, Numpy atau Pandas) telah mulai mengabaikan aturan di atas dan sebagai __repr__gantinya memberikan implementasi yang dapat dibaca manusia .

bluenote10
sumber
7

Dari buku Fluent Python :

Persyaratan dasar untuk objek Python adalah untuk menyediakan representasi string yang dapat digunakan sendiri, satu digunakan untuk debugging dan logging, yang lain untuk presentasi kepada pengguna akhir. Itu sebabnya
metode khusus __repr__dan __str__ada dalam model data.

Ijaz Ahmad Khan
sumber
5

Jawaban yang sangat baik sudah mencakup perbedaan antara __str__dan __repr__, yang bagi saya bermuara pada yang sebelumnya dapat dibaca bahkan oleh pengguna akhir, dan yang terakhir menjadi berguna bagi pengembang. Mengingat itu, saya menemukan bahwa implementasi standar __repr__sering gagal mencapai tujuan ini karena dihilangkan informasi yang berguna bagi pengembang.

Untuk alasan ini, jika saya memiliki yang cukup sederhana __str__, saya biasanya hanya mencoba untuk mendapatkan yang terbaik dari kedua dunia dengan sesuatu seperti:

def __repr__(self):
    return '{0} ({1})'.format(object.__repr__(self), str(self))
orome
sumber
4

Satu hal penting yang perlu diingat adalah bahwa __str__penggunaan kontainer mengandung objek __repr__.

>>> from datetime import datetime
>>> from decimal import Decimal
>>> print (Decimal('52'), datetime.now())
(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 51, 26, 185000))
>>> str((Decimal('52'), datetime.now()))
"(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 52, 22, 176000))"

Python lebih memilih ambiguitas daripada keterbacaan , __str__panggilan dari tuplepanggilan yang berisi objek __repr__, representasi "formal" dari suatu objek. Meskipun representasi formal lebih sulit dibaca daripada yang formal, itu tidak ambigu dan lebih kuat terhadap bug.

zangw
sumber
Ini digunakan __repr__ ketika ( __str__) tidak didefinisikan! Jadi kamu salah.
jiten
4

Pendeknya:

class Demo:
  def __repr__(self):
    return 'repr'
  def __str__(self):
    return 'str'

demo = Demo()
print(demo) # use __str__, output 'str' to stdout

s = str(demo) # __str__ is used, return 'str'
r = repr(demo) # __repr__ is used, return 'repr'

import logging
logger = logging.getLogger(logging.INFO)
logger.info(demo) # use __str__, output 'str' to stdout

from pprint import pprint, pformat
pprint(demo) # use __repr__, output 'repr' to stdout
result = pformat(demo) # use __repr__, result is string which value is 'str'
ShadowWalker
sumber
4
>>> print(decimal.Decimal(23) / decimal.Decimal("1.05"))
21.90476190476190476190476190
>>> decimal.Decimal(23) / decimal.Decimal("1.05")
Decimal('21.90476190476190476190476190')

Ketika print()dipanggil pada hasil decimal.Decimal(23) / decimal.Decimal("1.05")angka mentah dicetak; output ini dalam bentuk string yang dapat dicapai dengan __str__(). Jika kita cukup memasukkan ekspresi kita mendapatkan decimal.Decimaloutput - output ini dalam bentuk representasional yang dapat dicapai dengan __repr__(). Semua objek Python memiliki dua bentuk output. Bentuk string dirancang agar dapat dibaca oleh manusia. Bentuk representasional dirancang untuk menghasilkan keluaran yang jika diumpankan ke juru bahasa Python akan (bila mungkin) mereproduksi objek yang diwakili.

BattleDrum
sumber
4

__str__dapat dipanggil pada objek dengan memanggil str(obj)dan harus mengembalikan string yang dapat dibaca manusia.

__repr__dapat dipanggil pada suatu objek dengan memanggil repr(obj)dan harus mengembalikan objek internal (bidang objek / atribut)

Contoh ini dapat membantu:

class C1:pass

class C2:        
    def __str__(self):
        return str(f"{self.__class__.__name__} class str ")

class C3:        
    def __repr__(self):        
         return str(f"{self.__class__.__name__} class repr")

class C4:        
    def __str__(self):
        return str(f"{self.__class__.__name__} class str ")
    def __repr__(self):        
         return str(f"{self.__class__.__name__} class repr")


ci1 = C1()    
ci2 = C2()  
ci3 = C3()  
ci4 = C4()

print(ci1)       #<__main__.C1 object at 0x0000024C44A80C18>
print(str(ci1))  #<__main__.C1 object at 0x0000024C44A80C18>
print(repr(ci1)) #<__main__.C1 object at 0x0000024C44A80C18>
print(ci2)       #C2 class str
print(str(ci2))  #C2 class str
print(repr(ci2)) #<__main__.C2 object at 0x0000024C44AE12E8>
print(ci3)       #C3 class repr
print(str(ci3))  #C3 class repr
print(repr(ci3)) #C3 class repr
print(ci4)       #C4 class str 
print(str(ci4))  #C4 class str 
print(repr(ci4)) #C4 class repr
prosti
sumber
3

Memahami __str__dan __repr__secara intuitif dan permanen membedakan mereka sama sekali.

__str__mengembalikan string yang menyamarkan tubuh dari objek tertentu agar dapat dibaca mata
__repr__mengembalikan tubuh daging asli dari objek tertentu (mengembalikan dirinya sendiri) untuk mengidentifikasikan kerancuan.

Lihat dalam contoh

In [30]: str(datetime.datetime.now())
Out[30]: '2017-12-07 15:41:14.002752'
Disguised in string form

Mengenai __repr__

In [32]: datetime.datetime.now()
Out[32]: datetime.datetime(2017, 12, 7, 15, 43, 27, 297769)
Presence in real body which allows to be manipulated directly.

Kita dapat melakukan operasi aritmatika pada __repr__hasil dengan nyaman.

In [33]: datetime.datetime.now()
Out[33]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521)
In [34]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521) - datetime.datetime(2
    ...: 017, 12, 7, 15, 43, 27, 297769)
Out[34]: datetime.timedelta(0, 222, 443752)

jika menerapkan operasi pada __str__

In [35]: '2017-12-07 15:43:14.002752' - '2017-12-07 15:41:14.002752'
TypeError: unsupported operand type(s) for -: 'str' and 'str'

Tidak menghasilkan apa-apa selain kesalahan.

Contoh lain.

In [36]: str('string_body')
Out[36]: 'string_body' # in string form

In [37]: repr('real_body')
Out[37]: "'real_body'" #its real body hide inside

Semoga ini membantu Anda membangun alasan konkret untuk mengeksplorasi lebih banyak jawaban.

Kalkulus
sumber
3
  1. __str__harus mengembalikan objek string sedangkan __repr__dapat mengembalikan ekspresi python apa pun.
  2. Jika __str__implementasi hilang maka __repr__fungsi digunakan sebagai fallback. Tidak ada fallback jika __repr__implementasi fungsi hilang.
  3. Jika __repr__fungsi mengembalikan representasi String objek, kita bisa mengabaikan implementasi __str__fungsi.

Sumber: https://www.journaldev.com/22460/python-str-repr-functions

Sampath
sumber
2

__repr__digunakan di mana-mana, kecuali oleh printdan strmetode (ketika a __str__didefinisikan!)

techkuz
sumber