Pytanie Różnica między __str__ a __repr__?


Jaka jest różnica pomiędzy __str__ i __repr__ w Python?


2112
2017-09-17 04:27


pochodzenie




Odpowiedzi:


Alex dobrze podsumował, ale, co zaskakujące, był zbyt zwięzły.

Po pierwsze, chciałbym powtórzyć główne punkty Alex's post:

  • Domyślna implementacja jest bezużyteczna (ciężko wymyślić taką, która nie byłaby, ale tak)
  • __repr__ celem jest być jednoznacznym
  • __str__ celem jest być czytelnym
  • Pojemnik __str__ wykorzystuje zawarte obiekty " __repr__

Domyślna implementacja jest bezużyteczna

Jest to w większości niespodzianka, ponieważ domyślne wartości Pythona wydają się dość użyteczne. Jednak w tym przypadku o wartości domyślnej dla __repr__ który działałby jak:

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

byłoby zbyt niebezpieczne (na przykład zbyt łatwe do uzyskania nieskończonej rekursji, jeśli obiekty odnoszą się do siebie). Tak więc Python się rozprasza. Zauważ, że jest jeden domyślny, który jest prawdziwy: if __repr__ jest zdefiniowany, a __str__ nie jest, obiekt zachowa się tak, jakby __str__=__repr__.

Oznacza to, w prosty sposób: prawie każdy zaimplementowany obiekt powinien mieć funkcjonalność __repr__ to jest użyteczne do zrozumienia przedmiotu. Realizowanie __str__ jest opcjonalne: zrób to, jeśli potrzebujesz funkcji "ładnego druku" (na przykład, używanej przez generator raportów).

Celem __repr__ ma być jednoznaczny

Pozwól mi wyjść i powiedzieć to - nie wierzę w debuggery. Naprawdę nie wiem jak używać jakiegokolwiek debuggera i nigdy nie użyłem go poważnie. Ponadto uważam, że główną wadą debuggerów jest ich podstawowa natura - większość błędów, które debugowałem, zdarzyło się dawno temu, w odległej galaktyce. Oznacza to, że wierzę, z zapałem religijnym, w wyrąb lasów. Rejestrowanie jest siłą napędową każdego przyzwoitego systemu serwerów typu "zapomnij i zapomnij". Python ułatwia rejestrowanie: z niektórymi opakowaniami specyficznymi dla projektu wszystko, czego potrzebujesz, to

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)

Ale musisz zrobić ostatni krok - upewnij się, że każdy zaimplementowany obiekt ma przydatne repr, więc kod taki może po prostu działać. Dlatego pojawia się pytanie "eval": jeśli masz wystarczająco dużo informacji eval(repr(c))==coznacza to, że wiesz wszystko, o czym musisz wiedzieć c. Jeśli to dość łatwe, przynajmniej w niewyraźny sposób, zrób to. Jeśli nie, upewnij się, że masz wystarczająco dużo informacji c tak czy inaczej. Zwykle używam formatu eval-like: "MyClass(this=%r,that=%r)" % (self.this,self.that). Nie oznacza to, że można faktycznie skonstruować MyClass lub że są to właściwe argumenty konstruktora - ale jest to przydatna forma wyrażenia "to wszystko, co musisz wiedzieć o tym wystąpieniu".

Uwaga: użyłem %r powyżej, nie %s. Zawsze chcesz użyć repr() [lub %r formatowanie znaku, równoważnie] wewnątrz __repr__ wdrożenie, lub pokonujesz cel repr. Chcesz móc różnicować MyClass(3) i MyClass("3").

Celem __str__ jest czytelny

W szczególności nie ma być jednoznaczna - zauważ, że str(3)==str("3"). Podobnie, jeśli zaimplementujesz abstrakcję IP, jej wygląd przypominający 192.168.1.1 jest w porządku. Podczas wykonywania abstrakcji daty / czasu, str może być "2010/4/12 15:35:22", itp. Celem jest przedstawienie go w taki sposób, że użytkownik, a nie programista, chciałby go przeczytać. Pozbądź się bezużytecznych cyfr, udawaj, że jest jakąś inną klasą - o ile to wspiera czytelność, to jest poprawa.

Pojemnik __str__ wykorzystuje zawarte obiekty " __repr__

Wydaje się to zaskakujące, prawda? To trochę, ale jak czytelne

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

być? Nie bardzo. W szczególności ciągi w pojemniku mogłyby zbyt łatwo zakłócić jego reprezentację ciągów. W obliczu niejednoznaczności pamiętaj, że Python opiera się pokusie odgadnięcia. Jeśli chcesz zachować powyższe zachowanie podczas drukowania listy, po prostu

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

(prawdopodobnie możesz również dowiedzieć się, co zrobić ze słownikami.

Podsumowanie

Wprowadzić w życie __repr__ dla każdej klasy, którą zaimplementujesz. To powinno być drugą naturą. Wprowadzić w życie __str__ jeśli myślisz, że byłoby użyteczne mieć wersję z ciągami, która błądzi po stronie większej czytelności na korzyść większej niejednoznaczności.


2174
2018-04-13 00:56



Zdecydowanie nie zgadzam się z twoją opinią, że debugowanie nie jest drogą do zrobienia. Do programowania użyj debuggera (i / lub logowania), do rejestrowania wykorzystania produkcyjnego. Dzięki debuggerowi masz widok na wszystko, co poszło nie tak kiedy wystąpił problem. Możesz zobaczyć pełny obraz. Chyba że logujesz się WSZYSTKO, nie możesz tego zdobyć. Plus, jeśli rejestrujesz wszystko, co zamierzasz, musisz przebrnąć przez mnóstwo danych, aby uzyskać to, czego chcesz. - Samuel
Świetna odpowiedź (z wyjątkiem tego, że nie używamy debuggerów). Chciałbym tylko dodać link do tego inne pytania i odpowiedzi dotyczące str vs unicode w Pythonie 3 które mogą być istotne w dyskusji dla osób, które dokonały zmiany. - ThatAintWorking
", ".join(l) - wykorzystuje złą praktykę używania małej litery "L" jako nazwy zmiennej. Nie nauczajmy początkujących takich przykładów w autorytatywnych źródłach. - Nikolay Prokopyev
plus1 dla debuggerów są bezużyteczne i nie skalują się ani grosza. Zamiast tego uzyskaj przepustowość rejestrowania. I tak, to był dobrze napisany post. Okazało się __repr__ było to, czego potrzebowałem do debugowania. Dziękuję za pomoc. - personal_cloud


Moja zasada: __repr__ jest dla programistów, __str__ jest dla klientów.


370
2017-09-17 11:35





O ile nie zdecydujesz inaczej, większość klas nie ma przydatnych wyników:

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

Jak widać - bez różnicy i bez informacji poza klasą i obiektem id. Jeśli zastąpisz tylko jedno z dwóch ...:

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

jak widzisz, jeśli przesłonisz __repr__, to też jest używane __str__, ale nie na odwrót.

Inne ważne ciekawostki, które warto poznać: __str__ na wbudowanym kontenerze korzysta z __repr__NIE __str__, dla przedmiotów, które zawiera. I pomimo słów na temat, które można znaleźć w typowych dokumentach, prawie nikt nie zadaje sobie trudu __repr__ obiektów być ciągiem, który eval może wykorzystać do zbudowania równego obiektu (jest to po prostu zbyt trudne, a niewiedza, w jaki sposób dany moduł został faktycznie zaimportowany, uniemożliwia to w rzeczywistości).

Tak, moja rada: skup się na robieniu __str__ w sensie czytelnym dla człowieka, oraz __repr__ tak jednoznaczne, jak to tylko możliwe, nawet jeśli przeszkadza to niewyraźnemu celowi osiągnięcia __repr__jest zwracana wartość akceptowana jako wejście do __eval__!


319
2017-09-17 04:49



W moich testach jednostkowych zawsze to sprawdzam eval(repr(foo)) ocenia na obiekt równy foo. Masz rację, że nie będzie działać poza moimi testowymi przypadkami, ponieważ nie wiem, jak moduł jest importowany, ale przynajmniej gwarantuje, że działa on trochę przewidywalny kontekst. Myślę, że to dobry sposób na ocenę, czy wynik __repr__jest wystarczająco wyraźny. Zrobienie tego w teście jednostkowym również pomaga to zapewnić __repr__ śledzi zmiany w klasie. - Steven T. Snyder
Zawsze staram się to upewnić eval(repr(spam)) == spam (przynajmniej w odpowiednim kontekście), lub eval(repr(spam)) podnosi a SyntaxError. W ten sposób unikniesz zamieszania. (I to jest prawie true dla wbudowanych i większości stdlib, z wyjątkiem np. list rekurencyjnych, gdzie a=[]; a.append(a); print(eval(repr(a))) daje Ci [[Ellipses]]...) Oczywiście nie robię tego tak naprawdę posługiwać się  eval(repr(spam)), oprócz tego, że sprawdza się w testach jednostkowych ... ale ja zrobić czasami kopiuj i wklej repr(spam) w sesję interaktywną. - abarnert
plus 1 za wyjaśnienie tego __str__ jest realizowany pod kątem __repr__. Wydaje się być czymś, co inne posty przegapiły. - personal_cloud
Dlaczego nie używać kontenerów (list, krotek) __str__ dla każdego elementu zamiast __repr__? Wydaje mi się to niesłuszne, ponieważ zaimplementowałem czytelne __str__ w moim obiekcie i kiedy jest częścią listy, widzę brzydotę __repr__ zamiast. - SuperGeo


__repr__: reprezentacja obiektu Pythona zwykle eval przekonwertuje go z powrotem do tego obiektu

__str__: jest to, co uważasz za obiekt w formie tekstowej

na przykład

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





Krótko mówiąc, celem __repr__ ma być jednoznaczny i __str__ ma być   czytelny.

Oto dobry przykład:

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

Przeczytaj tę dokumentację dla repr:

repr(object)

Zwraca ciąg znaków zawierający drukowaną reprezentację obiektu. Jest to ta sama wartość uzyskana w wyniku konwersji (odwrotnie   cytaty). Czasem przydatne jest uzyskanie dostępu do tej operacji jako   zwykła funkcja. W przypadku wielu typów ta funkcja podejmuje próbę   zwrócić ciąg znaków, który dałby obiekt o tej samej wartości, kiedy   przeszedł do eval(), w przeciwnym razie reprezentacja jest łańcuchem zamkniętym w   nawiasy klamrowe zawierające nazwę typu obiektu   wraz z dodatkowymi informacjami często zawierającymi nazwę i   adres obiektu. Klasa może kontrolować, co ta funkcja zwraca   dla jego instancji definiując a __repr__() metoda.

Oto dokumentacja dla str:

str(object='')

Zwróć ciąg zawierający ładnie drukowany   reprezentacja obiektu. W przypadku łańcuchów zwraca ciąg znaków   samo. Różnica z repr(object)czy to str(object) nie   zawsze próbuj zwrócić ciąg, który jest akceptowalny eval(); jego   celem jest zwrócenie ciągów do wydrukowania. Jeśli nie podano argumentu, zwraca   pusty ciąg, ''.


115
2017-10-25 18:38





Jaka jest różnica pomiędzy __str__ i __repr__ w języku Python?

__str__ (czytaj jako ciąg "dunder (double-podkreślenia)") i __repr__ (czytane jako "dunder-repper" (dla "reprezentacji")) są specjalnymi metodami, które zwracają łańcuchy na podstawie stanu obiektu.

__repr__ zapewnia zachowanie kopii zapasowej, jeśli __str__ brakuje.

Tak więc należy najpierw napisać a __repr__ która pozwala na przywrócenie równoważnego obiektu z ciągu, który zwraca, np. za pomocą eval lub wpisując go w znak-znak w powłoce Pythona.

W dowolnym momencie można napisać a __str__ dla czytelnej dla użytkownika reprezentacji ciągów instancji, gdy ktoś uważa, że ​​jest to konieczne.

__str__

Jeśli wydrukujesz obiekt lub przekazujesz go format, str.format, lub str, a następnie jeśli __str__ metoda jest zdefiniowana, ta metoda zostanie wywołana, w przeciwnym razie __repr__ będzie użyty.

__repr__

The __repr__ metoda jest wywoływana przez funkcję wbudowaną repr i jest to, co jest echo w powłoce Pythona, gdy ocenia wyrażenie, które zwraca obiekt.

Ponieważ zapewnia kopię zapasową dla __str__, jeśli możesz napisać tylko jeden, zacznij od __repr__

Oto wbudowana pomoc na repr:

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

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

To znaczy, dla większości obiektów, jeśli wpiszesz to, co jest drukowane repr, powinieneś być w stanie stworzyć odpowiedni obiekt. Ale to nie jest domyślna implementacja.

Domyślna implementacja __repr__

Obiekt domyślny __repr__ jest (C Źródło Pythona) coś jak:

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

Oznacza to, że domyślnie wypiszesz moduł, z którego obiekt pochodzi, nazwę klasy i szesnastkową reprezentację jego położenia w pamięci - na przykład:

<__main__.Foo object at 0x7f80665abdd0>

Ta informacja nie jest zbyt użyteczna, ale nie ma sposobu, aby wyprowadzić, w jaki sposób można dokładnie stworzyć kanoniczną reprezentację danej instancji, i jest to lepsze niż nic, a przynajmniej mówi nam, jak możemy jednoznacznie zidentyfikować ją w pamięci.

Jak można __repr__ być przydatnym?

Spójrzmy, jak może być użyteczny, używając powłoki Pythona i datetime obiekty. Najpierw musimy zaimportować datetime moduł:

import datetime

Jeśli zadzwonimy datetime.now w powłoce zobaczymy wszystko, czego potrzebujemy do odtworzenia równoważnego obiektu datetime. Jest to tworzone przez datetime __repr__:

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

Jeśli wydrukujemy obiekt datetime, widzimy przyjemny ludzki czytelny (w rzeczywistości, ISO) format. Jest to realizowane przez datetime __str__:

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

Prostą sprawą jest odtworzenie obiektu, który utraciliśmy, ponieważ nie przypisaliśmy go do zmiennej przez skopiowanie i wklejenie z pliku __repr__ wyjście, a następnie wydrukowanie go, a my otrzymamy go w tym samym czytelny dla człowieka wynik jak drugi obiekt:

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

Jak mogę je wdrożyć?

W miarę rozwoju będziesz chciał odtwarzać obiekty w tym samym stanie, jeśli to możliwe. Jest to na przykład definicja obiektu datetime __repr__ (Źródło Pythona). Jest dość skomplikowany ze względu na wszystkie atrybuty potrzebne do odtworzenia takiego obiektu:

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

Jeśli chcesz, aby obiekt miał bardziej czytelną reprezentację, możesz go zaimplementować __str__ Kolejny. Oto jak obiekt datetime (Źródło Pythona) narzędzia __str__, co łatwo robi, ponieważ ma już funkcję wyświetlania w formacie ISO:

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

Zestaw __repr__ = __str__?

Jest to krytyka innej odpowiedzi, która sugeruje ustawienie __repr__ = __str__.

Oprawa __repr__ = __str__ jest głupie - __repr__ jest awarią dla __str__ i a __repr__, napisane dla programistów podczas debugowania, powinno zostać napisane przed napisaniem __str__.

Potrzebujesz __str__ tylko wtedy, gdy potrzebujesz tekstowej reprezentacji obiektu.

Wniosek

Definiować __repr__ w przypadku obiektów, które piszesz, abyś Ty i inni programiści mieli powtarzalny przykład, gdy używasz go w miarę rozwoju. Definiować __str__ kiedy potrzebujesz czytelnej dla człowieka reprezentacji smyczkowej.


85
2018-01-25 02:01





Oprócz wszystkich udzielonych odpowiedzi chciałbym dodać kilka punktów:

1) __repr__() jest wywoływana, gdy po prostu wpisujesz nazwę obiektu w interaktywnej konsoli pythona i wciskasz enter.

2) __str__() jest wywoływana, gdy używasz obiektu z instrukcją print.

3) W przypadku, jeśli __str__ brakuje, a następnie wydrukuj i użyj dowolnej funkcji str() przywołuje __repr__() przedmiotu.

4) __str__() kontenerów, po wywołaniu zostanie wykonany __repr__() metoda zawartych w nim elementów.

5) str() wzywany w ciągu __str__() może potencjalnie rekurencyjnie bez przypadku podstawowego i błąd na maksymalnej głębokości rekursji.

6) __repr__() mogę zadzwonić repr() który będzie próbował automatycznie uniknąć nieskończonej rekurencji, zastępując obiekt już reprezentowany ....


12
2017-09-08 03:27