Soru __Str__ ve __repr__ arasındaki fark?


Arasındaki fark nedir __str__ ve __repr__ içinde Python?


2112
2017-09-17 04:27


Menşei




Cevaplar:


Alex iyi özetlendi, ama şaşırtıcı bir şekilde, çok özlü idi.

İlk olarak, ana noktaları tekrar tekrar söyleyeyim Alex’in gönderisi:

  • Varsayılan uygulama işe yaramıyor (olmayacak olanı düşünmek zordur, ama evet)
  • __repr__ amaç açık olmaktır
  • __str__ amaç okunabilir olmaktır
  • Konteyner en __str__ içerilen nesneleri kullanır __repr__

Varsayılan uygulama işe yaramaz

Bu çoğunlukla bir sürpriz, çünkü Python’un varsayılanları oldukça faydalıdır. Ancak, bu durumda, __repr__ Hangi gibi davranacak:

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

Çok tehlikeli olurdu (örneğin, nesneler birbirlerine referans veriyorsa sonsuz yinelemeye girmek çok kolay). Yani Python polisler. Doğru olan bir varsayılan değer olduğunu unutmayın: eğer __repr__ tanımlı ve __str__ değil, nesne sanki gibi davranacak __str__=__repr__.

Bu, basit bir ifadeyle, uygulayacağınız neredeyse her nesnenin işlevsel olması gerektiği anlamına gelir. __repr__ Bu, nesneyi anlamak için kullanılabilir. Uygulama __str__ isteğe bağlıdır: “güzel yazdırma” işlevine gereksiniminiz varsa (örneğin, bir rapor üreticisi tarafından kullanılır).

Amacı __repr__ net olmak

Sağ çıkıp söyleyeyim - hata ayıklayıcılarına inanmıyorum. Herhangi bir hata ayıklayıcısını nasıl kullanacağımı gerçekten bilmiyorum ve hiç birini ciddi kullanmadım. Ayrıca, hata ayıklayıcısındaki büyük hataların temel doğaları olduğuna inanıyorum - hata ayıkladığım hataların çoğu uzun zaman önce çok uzak bir galakside gerçekleşti. Bu demek oluyor ki, dinsel şevkle günlüğe inanıyordum. Günlüğe kaydetme, iyi bir yangın ve unut-unut sunucu sisteminin can damarıdır. Python, günlüğe kaydetmeyi kolaylaştırır: belki de bazı projeye özgü paketleyicilerle, tek ihtiyacınız olan şey

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)

Ancak, son adımı yapmanız gerekir - uyguladığınız her nesnenin yararlı bir kopyaya sahip olduğundan emin olun, bu nedenle böyle bir kod işe yarayabilir. Bu yüzden “eval” olayı ortaya çıkıyor: eğer yeterli bilgiye sahipseniz eval(repr(c))==cBu, bilmeniz gereken her şeyi bildiğiniz anlamına gelir c. Bu yeterince kolaysa, en azından bulanık bir şekilde yapın. Değilse, hakkında yeterli bilgiye sahip olduğunuzdan emin olun. c neyse. Genellikle bir eval-like formatı kullanırım: "MyClass(this=%r,that=%r)" % (self.this,self.that). Bu, MyClass'ı gerçekten oluşturabileceğiniz anlamına gelmez, ya da bunlar doğru yapıcı argümanlarıdır - ama “bu örnek hakkında bilmeniz gereken her şey budur” ifadesinin faydalı bir şeklidir.

Not: kullandım %r yukarıda değil %s. Her zaman kullanmak istersiniz repr() [veya %r formatlama karakteri, eşdeğer] __repr__ uygulama veya repr'nin hedefini yeniyorsunuz. Farklılaşabilmeyi istiyorsun MyClass(3) ve MyClass("3").

Amacı __str__ okunabilir olmak

Spesifik olarak, açık bir şekilde anlaşılması amaçlanmamıştır. str(3)==str("3"). Benzer şekilde, bir IP soyutlaması uygularsanız, bunun str'si 192.168.1.1 gibi görünüyor. Bir tarih / zaman soyutlamasını uygularken, str "2010/4/12 15:35:22", vb. Olabilir. Amaç, bir programcının değil, bir kullanıcının onu okumak isteyeceği şekilde temsil etmektir. Kullanılamayan basamakları keser, başka bir sınıf gibi davranır - okunabilirliği desteklediği sürece, bu bir gelişmedir.

Konteyner en __str__ içerilen nesneleri kullanır __repr__

Bu şaşırtıcı görünüyor, değil mi? Bu biraz, ama ne kadar okunabilir olurdu

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

olabilir mi? Çok değil. Özellikle, bir kaptaki dizgiler, dizge gösterimini rahatsız etmenin çok kolay bir yolunu bulacaktır. Belirsizlik karşısında, Python tahmin etme isteğine direnir. Bir listeyi yazdırırken yukarıdaki davranışı istiyorsanız, sadece

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

(muhtemelen sözlükler hakkında ne yapacağınızı da anlayabilirsiniz.

özet

uygulamak __repr__ uyguladığınız herhangi bir sınıf için. Bu ikinci doğa olmalı. uygulamak __str__ Eğer daha fazla okunabilirliğin yanında daha fazla okunabilirlik lehinde yanıltıcı bir dize versiyonuna sahip olmanın faydalı olacağını düşünürseniz.


2174
2018-04-13 00:56



Kesinlikle hata ayıklamanın gitmenin yolu olmadığını düşüncesine katılmıyorum. Geliştirme için üretim kullanım kaydı için bir hata ayıklayıcı (ve / veya günlüğe kaydetme) kullanın. Hata ayıklayıcıda, sorun oluştuğunda yanlış giden her şeyin bir görünümü vardır. Resmin tamamını görebilirsiniz. HER ŞEY günlüğe kaydetmediğiniz sürece bunu alamazsınız. Artı, her şeyi günlüğe kaydediyorsan, istediğin şeyi elde etmek için tonlarca veriye dayanmak zorunda. - Samuel
Büyük cevap (hata ayıklayıcı kullanmama hakkında biraz hariç). Sadece buna bir link eklemek istiyorum diğer Soru-Cevap str vs unicode Python 3 içinde Bu, anahtarı yapan insanlar için tartışmaya uygun olabilir. - ThatAintWorking
", ".join(l) - Değişken adı olarak küçük harf "L" kullanarak kötü uygulama kullanır. Yetkili kaynaklarda bu tür örneklerin programlanmasını öğretmeyelim. - Nikolay Prokopyev
Hata ayıklayıcılar için plus1 işe yaramaz ve bir kuruşa değmez. Bunun yerine kayıt işlemlerinizi artırın. Ve evet bu iyi yazılmış bir yazıydı. Çıkıyor __repr__ hata ayıklamak için ihtiyacım olan şeydi. Yardımın için teşekkürler. - personal_cloud


Benim temel kuralım: __repr__ geliştiriciler içindir __str__ müşteriler içindir.


370
2017-09-17 11:35





Aksi halde emin olmak için harekete geçmedikçe, çoğu sınıfın ya da için yararlı sonuçları yoktur:

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

Gördüğünüz gibi - hiçbir fark ve sınıf ve nesnenin ötesinde hiçbir bilgi id. İkisinden birini geçersiz kılarsanız ...:

>>> 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>
>>> 

gördüğünüz gibi, geçersiz kıldığınızda __repr__, bu ALSO için kullanılır __str__ama tersi değil.

Bilmeniz gereken diğer önemli bilgiler: __str__ yerleşik bir kapta kullanır __repr__, Değil __str__içerdiği öğeler için. Ve konuyla ilgili tipik doktorlarda bulunan kelimelere rağmen, hiç kimse rahatsız ediyor __repr__ nesnelerin bir dizesi olması eval Eşit bir nesne oluşturmak için kullanabilir (sadece çok zor, VE ilgili modülün gerçekte nasıl ithal edildiğini bilmemek aslında imkansızlaştırır).

Yani, benim tavsiyem: yapmaya odaklanın __str__ makul olarak insan tarafından okunabilir ve __repr__ Yapabileceğimiz kadar açık değil, bu, yapamayan belirsiz hedefe engel olsa bile __repr__giriş değeri kabul edilen değer olarak kabul edilebilir __eval__!


319
2017-09-17 04:49



Benim birim testlerimde her zaman kontrol ederim eval(repr(foo)) eşit olan bir nesneyi değerlendirir foo. Modülün nasıl alındığını bilmediğimden, test durumlarımın dışında çalışmayacağına inanıyorum; bazı öngörülebilir bağlam. Bunun sonucunun değerlendirilmesi için iyi bir yol olduğunu düşünüyorum. __repr__yeterince açık. Bunu bir birim testinde yapmak aynı zamanda __repr__ sınıftaki değişiklikleri takip eder. - Steven T. Snyder
Ben her zaman ya eval(repr(spam)) == spam (en azından doğru bağlamda) veya eval(repr(spam)) a yükseltir SyntaxError. Bu şekilde karışıklığı önlersiniz. (Ve bu neredeyse yerleşikler ve stdlib'in çoğu için doğrudur, örneğin, özyinelemeli listeler hariç, a=[]; a.append(a); print(eval(repr(a))) sana verir [[Ellipses]]…) Tabii ki bunu aslında yapmayacağım kullanım  eval(repr(spam))ünite testlerinde akıl sağlığı kontrolü dışında… ama ben yap bazen kopyala yapıştır repr(spam) interaktif bir oturuma. - abarnert
bunu açıklamak için plus1 __str__ açısından uygulanmaktadır __repr__. Diğer mesajların kaçırdığı bir şey gibi görünüyor. - personal_cloud
Neden kaplar (listeler, kopyalar) kullanmaz? __str__ yerine her bir öğe için __repr__? Okunabilir bir şekilde uygulandığım için bana yanlış geliyor __str__ benim neslimde ve bir listenin bir parçası olduğunda ben çirkin görüyorum __repr__ yerine. - SuperGeo


__repr__: python nesnesinin gösterimi genellikle eval, onu tekrar bu nesneye dönüştürecektir

__str__: Metin formundaki bu nesne ne düşünüyorsun

Örneğin.

>>> 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

143
2017-09-17 04:35





Kısacası, amacı __repr__ açık ve net olmaktır __str__ olmak   okunabilir.

İşte güzel bir örnek:

>>> 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)'

Repr için şu belgeleri okuyun:

repr(object)

Bir nesnenin yazdırılabilir bir temsilini içeren bir dizgi döndürür. Bu, dönüşümlerle elde edilen aynı değerdir (tersi)   tırnak). Bu işleme şu şekilde erişebilmek bazen yararlıdır   sıradan bir işlev. Birçok türde, bu işlev bir girişim yapar   aynı değere sahip bir nesneyi veren bir dizge döndürmek   geçirilen eval()Aksi takdirde temsil, içinde bulunan bir dizedir.   nesnenin türünü içeren açılı ayraçlar   genellikle isim ve   nesnenin adresi. Bir sınıf, bu işlevin geri döndüğünü kontrol edebilir   Örneklerini tanımlayarak __repr__() yöntem.

İşte str için belgeler:

str(object='')

Güzel bir şekilde yazdırılabilir bir dizgi döndür   bir nesnenin gösterimi. Dizeler için bu dizgeyi döndürür   kendisi. İle fark repr(object)bu mu str(object) değil   her zaman kabul edilebilir bir dizge döndürmeyi dener eval(); onun   hedef yazdırılabilir bir dizgi döndürmektir. Hiçbir argüman verilmediyse, döner   boş dize ''.


115
2017-10-25 18:38





Arasındaki fark nedir __str__ ve __repr__ Python'da mı?

__str__ ("dunder (çift alt çizgi)" olarak okunur) __repr__ ("dunder-repper" olarak okunur) ("temsil" için)), nesnenin durumuna bağlı olarak dizeleri döndüren özel yöntemlerdir.

__repr__ yedekleme davranışı sağlarsa __str__ kayıp.

Yani önce bir tane yazmalı __repr__ Bu, eşdeğer bir nesneyi döndürdüğünüz dizeden eşdeğer bir nesneyi yeniden etkinleştirmenizi sağlar. kullanma eval veya bir Python kabuğundaki karakter karakterine yazarak.

Herhangi bir zamanda, bir yazabilirsiniz __str__ Birinin gerekli olduğuna inandığı zaman, kullanıcının okunabilir bir dize temsili için.

__str__

Bir nesneyi yazdırırsanız veya format, str.formatveya streğer öyleyse __str__ yöntem tanımlanır, aksi halde yöntem çağrılır __repr__ kullanılacak.

__repr__

__repr__ yöntem yerleşik işlev tarafından çağrılır repr ve bir nesneyi döndüren bir ifadeyi değerlendirdiğinde, python kabuğunda yankılanan şeydir.

İçin bir yedek sağladığından __str__eğer sadece bir tane yazabilirseniz __repr__

İşte yerleşik yardım repr:

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

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

Yani, çoğu nesne için, ne yazdığıyla yazıyorsanız repreşdeğer bir nesne oluşturabilmelisiniz. Ancak bu varsayılan uygulama değildir.

Varsayılan Uygulaması __repr__

Varsayılan nesne __repr__ (C Python kaynağı) gibi bir şey:

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

Bu, varsayılan olarak, nesnenin bulunduğu modülden, sınıf adı ve bellekteki konumunun onaltılık temsilini yazdıracağınız anlamına gelir - örneğin:

<__main__.Foo object at 0x7f80665abdd0>

Bu bilgi pek kullanışlı değil, ancak herhangi birinin belirli bir örneğin kanonik bir temsilini nasıl doğru bir şekilde oluşturabildiğini ortaya çıkarmanın bir yolu yok, ve hiç değilse, en azından belleğimizde nasıl benzersiz bir şekilde tanımlayabileceğimizi anlatıyor.

Nasıl olabilir __repr__ Bir işe yara?

Python kabuğunu kullanarak ne kadar kullanışlı olabileceğine bakalım. datetime nesneler. İlk önce datetime modülü:

import datetime

Eğer ararsak datetime.now Kabukta, eşdeğer bir datetime nesnesini yeniden oluşturmak için ihtiyacımız olan her şeyi göreceğiz. Bu datetime tarafından oluşturuldu __repr__:

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

Bir datetime nesnesini yazdırırsak, iyi bir insan okunabilir (aslında, ISO) formatı görürüz. Bu datetime tarafından uygulanır __str__:

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

Kaybettiğimiz nesneyi yeniden oluşturmak basit bir meseledir çünkü biz onu kopyalayıp yapıştırarak bir değişkene atamadık. __repr__ çıktısını alıp yazdırıyor ve diğer nesne ile aynı insan okunabilir çıktısını alıyoruz:

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

Bunları nasıl uygularım?

Gelişmekte olduğunuzda, mümkünse, aynı durumda nesneleri yeniden üretmek isteyeceksiniz. Bu, örneğin, datetime nesnesinin nasıl tanımlandığını tanımlar __repr__ (Python kaynağı). Böyle bir nesneyi çoğaltmak için gereken tüm özelliklerden dolayı oldukça karmaşıktır:

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 = ", ".join(map(str, L))
    s = "%s(%s)" % ('datetime.' + self.__class__.__name__, s)
    if self._tzinfo is not None:
        assert s[-1:] == ")"
        s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
    return s

Nesnenin daha okunabilir bir temsiliyetine sahip olmasını istiyorsanız, uygulayabilirsiniz. __str__ Sonraki. İşte datetime nesnesinin nasıl olduğuPython kaynağı) uygular __str__Kolayca yapar çünkü zaten ISO formatında görüntülemek için bir işlevi vardır:

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

Set __repr__ = __str__?

Bu, başka bir cevabın burada bir ayar önerdiğinin bir eleştirisidir. __repr__ = __str__.

Ayar __repr__ = __str__ Aptalca - __repr__ için bir düşüş __str__ ve bir __repr__, hata ayıklamada geliştiriciler için yazılmış, yazmadan önce yazılmalıdır. __str__.

Bir ihtiyacın var __str__ sadece nesnenin metinsel gösterimi gerektiğinde.

Sonuç

Tanımlamak __repr__ Yazdığınız nesneler için, siz ve diğer geliştiricilerin, geliştirirken kullandığınız şekilde tekrarlanabilir bir örneği vardır. Tanımlamak __str__ bir insan okunabilir dize gösterimi gerektiğinde.


85
2018-01-25 02:01





Verilen tüm cevaplardan ayrı olarak birkaç nokta eklemek istiyorum:

1) __repr__() Etkileşimli python konsolunda nesnenin adını yazdığınızda ve enter tuşuna basıldığında çağrılır.

2) __str__() yazdırma ifadesiyle nesne kullandığınızda çağrılır.

3) durumda __str__ eksik, sonra yazdırma ve herhangi bir işlevi kullanarak str() çağırır __repr__() nesnenin

4) __str__() kapsayıcı, çalıştırıldığında çalıştırılacak __repr__() İçerdiği elemanların yöntemi.

5) str() içinde aradı __str__() Bir temel durum olmadan potansiyel olarak tekrarlanabilir ve maksimum yineleme derinliğinde hata olabilir.

6) __repr__() arayabilir repr() sonsuz yinelemeden kaçınmaya çalışacak, önceden belirlenmiş bir nesnenin ....


12
2017-09-08 03:27