Różnica między __str__ a __repr__?

Odpowiedzi:

2723

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

Po pierwsze, chciałbym powtórzyć główne punkty w poście Alexa :

  • Domyślna implementacja jest bezużyteczna (trudno pomyśleć o takiej, która nie byłaby, ale tak)
  • __repr__ celem jest być jednoznacznym
  • __str__ celem jest być czytelnym
  • Kontenera __str__zastosowania zawarte obiekty__repr__

Domyślna implementacja jest bezużyteczna

Jest to głównie niespodzianka, ponieważ domyślne ustawienia Pythona są zwykle dość przydatne. Jednak w tym przypadku ustawienie domyślne, dla __repr__którego działałoby jak:

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

byłby zbyt niebezpieczny (na przykład zbyt łatwy do wejścia w nieskończoną rekurencję, jeśli obiekty się nawzajem odwołują). Python więc sobie radzi. Zauważ, że istnieje jedna wartość domyślna, która jest prawdziwa: jeśli __repr__jest zdefiniowana i __str__nie ma, obiekt będzie zachowywał się tak, jakby __str__=__repr__.

W skrócie oznacza to: prawie każdy zaimplementowany obiekt powinien mieć funkcję __repr__przydatną do zrozumienia obiektu. Wdrożenie __str__jest opcjonalne: zrób to, jeśli potrzebujesz funkcji „ładnego wydruku” (na przykład używanej przez generator raportów).

Celem __repr__jest być jednoznacznym

Pozwól mi od razu powiedzieć i powiedzieć - nie wierzę w debuggery. Naprawdę nie wiem, jak korzystać z jakiegokolwiek debuggera i nigdy nie użyłem go poważnie. Co więcej, uważam, że wielką wadą debuggerów jest ich podstawowa natura - większość błędów, które debugowałem, miały miejsce dawno temu, w odległej galaktyce. Oznacza to, że wierzę, z zapałem religijnym, w pozyskiwanie drewna. Rejestrowanie jest siłą napędową każdego przyzwoitego systemu serwerów typu „zapomnij o pożarze i zapomnieniu”. Python ułatwia logowanie: w przypadku niektórych opakowań specyficznych 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 rep, więc taki kod może po prostu działać. Oto dlaczego pojawia się „ewaluacja”: jeśli masz wystarczająco dużo informacji eval(repr(c))==c, oznacza to, że wiesz wszystko, o czym można wiedzieć c. Jeśli to wystarczająco łatwe, przynajmniej w niewyraźny sposób, zrób to. Jeśli nie, upewnij się, że i tak masz wystarczająco dużo informacji c. Zwykle używam eval-Like formacie: "MyClass(this=%r,that=%r)" % (self.this,self.that). Nie oznacza to, że możesz zbudować MyClass, ani że są to odpowiednie argumenty konstruktora - ale jest to przydatna forma wyrażenia „to wszystko, co musisz wiedzieć o tym wystąpieniu”.

Uwaga: użyłem %rpowyżej, nie %s. Zawsze chcesz użyć repr()[lub %rformatowania znaku, równoważnie] wewnątrz __repr__implementacji, albo pokonujesz cel repr. Chcesz być w stanie różnicować MyClass(3)i MyClass("3").

Celem __str__jest bycie czytelnym

W szczególności nie jest to jednoznaczne - zauważ to str(3)==str("3"). Podobnie, jeśli zaimplementujesz abstrakcję IP, posiadanie jej łańcucha wygląda tak, jakby 192.168.1.1 było w porządku. Podczas implementowania abstrakcji daty / godziny ciąg może mieć postać „2010/4/12 15:35:22” itp. Celem jest przedstawienie go w taki sposób, aby użytkownik, a nie programista, chciał go przeczytać. Odcinaj bezużyteczne cyfry, udawaj, że to inna klasa - o ile obsługuje czytelność, jest to poprawa.

Kontenera __str__zastosowania zawarte obiekty__repr__

To wydaje się zaskakujące, prawda? To trochę, ale jak by to było czytelne, gdyby użył ich __str__?

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

Nie bardzo. W szczególności łańcuchy w kontenerze zbyt łatwo zakłócałyby jego reprezentację łańcucha. Pamiętaj, że w obliczu niejasności Python opiera się pokusie zgadywania. Jeśli chcesz powyższe zachowanie podczas drukowania listy, po prostu

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

(prawdopodobnie możesz także dowiedzieć się, co zrobić z słownikami.

Podsumowanie

Implementuj __repr__dla dowolnej implementowanej klasy. To powinna być druga natura. Zaimplementuj, __str__jeśli uważasz, że przydałaby się wersja łańcuchowa, która popsuła się po stronie czytelności.

moshez
źródło
154
Zdecydowanie nie zgadzam się z opinią, że debugowanie nie jest dobrym rozwiązaniem. Do programowania użyj debugera (i / lub logowania), do logowania do celów produkcyjnych. Za pomocą debugera masz widok wszystkiego, co poszło nie tak, gdy wystąpił problem. Możesz zobaczyć pełny obraz. Dopóki nie rejestrujesz WSZYSTKO, nie możesz tego uzyskać. Plus, jeśli rejestrujesz wszystko, musisz przebrnąć przez mnóstwo danych, aby uzyskać to, czego chcesz.
Samuel
21
Świetna odpowiedź (z wyjątkiem tego, że nie używa debugerów). Chciałbym tylko dodać link do tego innego pytania i odpowiedzi na temat str vs unicode w Pythonie 3, które mogą być istotne w dyskusji dla osób, które dokonały zmiany.
ThatAintWorking
11
Plus1 dla debuggerów jest bezużyteczny i nie skaluje się ani grosza. Zamiast tego zwiększ przepustowość logowania. I tak, to był dobrze napisany post. Okazało się, __repr__że potrzebowałem do debugowania. Dziękuję za pomoc
personal_cloud
7
odkładając na bok głupotę debugera, nauczyłem się% r i to i tak warte jest głosowania
Mickey Perlstein
6
na temat debuggera kontra żaden debugger: nie otrzymuj tak głęboko zakorzenionych opinii. W niektórych aplikacjach debugowanie nie jest realistyczne, zwykle przy zaangażowaniu czasu rzeczywistego lub gdy kod jest wykonywany zdalnie tylko na platformie z małym dostępem lub bez konsoli. W większości innych przypadków o wiele szybciej będzie zatrzymać się na wyjściu w celu zbadania lub ustawić punkt przerwania, ponieważ nie trzeba przechodzić przez tysiące wierszy rejestrowania (co zaśmieci dysk i spowolni działanie aplikacji). Wreszcie, nie zawsze można się zalogować, na przykład na urządzeniach osadzonych, tam debugger jest również twoim przyjacielem.
RedGlyph
523

Moja ogólna zasada: __repr__jest dla programistów, __str__jest dla klientów.

Ned Batchelder
źródło
2
Jest to prawda, ponieważ dla obj = uuid.uuid1 (), obj .__ str __ () to „2d7fc7f0-7706-11e9-94ae-0242ac110002”, a obj .__ repr __ () to „UUID ('2d7fc7f0-7706-11e9-94ae-0242ac110002 „)”. Deweloperzy potrzebują (wartość + pochodzenie), podczas gdy klienci potrzebują wartości i nie dbają o to, jak ją dostali!
Naren Yellavula
1
Tutaj klient niekoniecznie musi oznaczać użytkownika końcowego. To klient lub użytkownik obiektu. Więc jeśli jest to SDK, to programiści SDK będą go używać, __str__więc normalni programiści mają czytelny obiekt. Z drugiej strony __repr__jest dla samych programistów SDK.
Shiplu Mokaddim
398

O ile nie zdecydujesz się inaczej, większość klas nie przyniesie pomocnych rezultatów dla:

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

Jak widzisz - bez różnicy i bez informacji poza klasą i przedmiotem id. Jeśli zastąpisz tylko jeden 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 TAKŻE zostanie użyte __str__, ale nie odwrotnie.

Inne ważne ciekawostki, które warto wiedzieć: __str__na wbudowanym pojemniku używa __repr__, a NIE __str__, przedmiotów, które zawiera. I pomimo słów na ten temat znalezionych w typowych dokumentach, prawie nikt nie zadaje sobie trudu, aby __repr__obiekty z były ciągiem, który evalmoże posłużyć do zbudowania równego obiektu (jest to po prostu zbyt trudne, ORAZ nie wiedząc, w jaki sposób dany moduł został zaimportowany, sprawia, że ​​tak naprawdę całkowicie niemożliwe).

Moja rada: skup się na tym, aby __str__czytelnie czytelny dla ludzi i __repr__tak jednoznaczny, jak to tylko możliwe, nawet jeśli koliduje to z niewyraźnym, nieosiągalnym celem polegającym na tym __repr__, aby zwracana wartość była akceptowalna jako wkład __eval__!

Alex Martelli
źródło
34
W moich testach jednostkowych zawsze sprawdzam, czy eval(repr(foo))wartość jest równa obiektowi foo. Masz rację, że nie będzie działać na zewnątrz z moich testów, ponieważ nie wiem jak moduł jest importowany, ale ten przynajmniej zapewnia, że pracuje w jakimś przewidywalnym kontekście. Myślę, że to dobry sposób oceny, czy wynik __repr__jest wystarczająco wyraźny. Wykonanie tego w teście jednostkowym pomaga również upewnić się, że __repr__następuje zmiana w klasie.
Steven T. Snyder
4
Zawsze staram się upewnić, że albo eval(repr(spam)) == spam(przynajmniej w odpowiednim kontekście), albo eval(repr(spam))podnosi SyntaxError. W ten sposób unikniesz zamieszania. (I to jest prawie prawdziwe 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, że nie robię tego, aby użyć eval(repr(spam)) , z wyjątkiem sprawdzania poczytalności w testach jednostkowych… ale ja czy czasami skopiować i wkleić repr(spam)w sesji interaktywnej.
abarnert
Dlaczego pojemniki (listy, krotki) nie miałyby używać __str__dla każdego elementu zamiast __repr__? Wydaje mi się to zupełnie błędne, ponieważ zaimplementowałem obiekt czytelny __str__w moim obiekcie, a gdy jest on częścią listy, widzę brzydszy __repr__.
SuperGeo,
Po prostu wpadł irytujące bug związany z faktem, że eval(repr(x))zawodzi nawet dla typów wbudowanych: class A(str, Enum): X = 'x'podniesie SyntaxError na eval(repr(A.X)). To smutne, ale zrozumiałe. BTW, eval(str(A.X))faktycznie działa, ale oczywiście tylko wtedy, gdy class Ajest objęty zakresem - więc prawdopodobnie nie jest bardzo przydatny.
maks.
@SuperGeo Inne odpowiedzi obejmują: strelement użycia kontenera, reprponieważ [1, 2, 3]! = ["1", "2, 3"].
mtraceur,
163

__repr__: reprezentacja obiektu python zwykle eval przekonwertuje go z powrotem na ten obiekt

__str__: to, co myślisz, to ten 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
Andrew Clark
źródło
151

Krótko mówiąc, celem __repr__jest być jednoznacznym i __str__czytelnym.

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 zawierający reprezentację drukowalną obiektu. Jest to ta sama wartość, jaką dają konwersje (odwrotne wyceny). Czasami przydaje się dostęp do tej operacji jako zwykłej funkcji. W przypadku wielu typów ta funkcja podejmuje próbę zwrócenia ciągu, który dałby obiekt o tej samej wartości po przekazaniu eval(), w przeciwnym razie reprezentacja jest ciągiem zamkniętym w nawiasach kątowych, który zawiera nazwę typu obiektu wraz z dodatkowymi informacjami często w tym nazwa i adres obiektu. Klasa może kontrolować, co ta funkcja zwraca dla swoich instancji, poprzez zdefiniowanie __repr__()metody.

Oto dokumentacja dla str:

str(object='')

Zwraca ciąg znaków zawierający ładnie drukowaną reprezentację obiektu. W przypadku ciągów zwraca to sam ciąg. Różnica repr(object)polega na tym, str(object)że nie zawsze próbuje zwrócić ciąg akceptowalny eval(); jego celem jest zwrócenie drukowalnego ciągu. Jeżeli nie podano żadnych argumentów, zwraca pusty ciąg, ''.

bitoffdev
źródło
1
Jakie znaczenie ma tutaj ciąg do druku? Czy możesz to wyjaśnić?
Vicrobot,
115

Jaka jest różnica między __str__i __repr__w Pythonie?

__str__(czytane jako „ciąg dunder (podwójny podkreślnik)”) i __repr__(czytane jako „dunder-repper” (dla „reprezentacji”)) są specjalnymi metodami zwracającymi ciągi znaków na podstawie stanu obiektu.

__repr__zapewnia zachowanie kopii zapasowej, jeśli __str__brakuje.

Dlatego najpierw należy napisać taki, __repr__który pozwala przywrócić równoważny obiekt z ciągu, który zwraca, np. Używając evallub wpisując go znak po znaku w powłoce Pythona.

W dowolnym momencie można napisać __str__reprezentację instancji w postaci czytelnej dla użytkownika, jeśli uważa się to za konieczne.

__str__

W przypadku drukowania obiektu, lub przekazać go do format, str.formatlub str, następnie, jeśli __str__metoda jest zdefiniowana, że metoda będzie wywoływana, w przeciwnym razie __repr__zostaną wykorzystane.

__repr__

__repr__Metoda jest wywoływana przez funkcję wbudowanego repri to, co jest echem od powłoki Pythona gdy ocenia wyrażenie zwraca obiekt.

Ponieważ stanowi kopię zapasową __str__, jeśli możesz tylko napisać jedną, zacznij od__repr__

Oto wbudowana pomoc dotycząca 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ć równoważny obiekt. Ale to nie jest domyślna implementacja.

Domyślna implementacja __repr__

Domyślnym obiektem __repr__jest ( C Python source ) coś takiego:

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

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

<__main__.Foo object at 0x7f80665abdd0>

Informacje te nie są zbyt przydatne, ale nie ma sposobu, aby wywnioskować, w jaki sposób można dokładnie stworzyć kanoniczną reprezentację dowolnej instancji, i jest to lepsze niż nic, przynajmniej mówi nam, jak możemy jednoznacznie zidentyfikować je w pamięci.

Jak może __repr__być przydatny?

Zobaczmy, jak może być użyteczne, używając powłoki i datetimeobiektów Pythona . Najpierw musimy zaimportować datetimemoduł:

import datetime

Jeśli wywołamy datetime.nowpowłokę, 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, zobaczymy ładny format czytelny dla człowieka (w rzeczywistości ISO). Jest to realizowane przez datetime __str__:

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

Odtworzenie utraconego obiektu jest proste, ponieważ nie przypisaliśmy go do zmiennej przez skopiowanie i wklejenie z __repr__wyjścia, a następnie wydrukowanie, i otrzymujemy to samo wyjście czytelne dla człowieka, co drugi obiekt:

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

Jak je wdrożyć?

W miarę rozwoju będziesz chciał, jeśli to możliwe, być w stanie odtwarzać obiekty w tym samym stanie. Tak na przykład definiuje się obiekt datetime __repr__( źródło Python ). Jest dość złożony, ponieważ ma 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 = "%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

Jeśli chcesz, aby Twój obiekt miał bardziej czytelną dla człowieka reprezentację, możesz zaimplementować __str__następny. Oto jak implementuje obiekt datetime ( źródło Python ) __str__, co łatwo robi, ponieważ ma już funkcję wyświetlania go w formacie ISO:

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

Set __repr__ = __str__?

To jest krytyka innej odpowiedzi, która sugeruje ustawienie __repr__ = __str__.

Ustawienie __repr__ = __str__jest głupie - __repr__jest awarią, __str__a __repr__napisane dla deweloperów podczas debugowania powinno być napisane przed napisaniem __str__.

Potrzebujesz __str__tylko wtedy, gdy potrzebujesz tekstowej reprezentacji obiektu.

Wniosek

Zdefiniuj __repr__obiekty, które piszesz, abyś ty i inni programiści mieli powtarzalny przykład, kiedy używasz go podczas tworzenia. Zdefiniuj, __str__kiedy potrzebujesz czytelnej dla człowieka reprezentacji ciągu.

Aaron Hall
źródło
Czy nie powinno to być coś podobnego type(obj).__qualname__?
Solomon Ucko
@ SolomonUcko tak w Pythonie 3, wydaje się, że tak właśnie jest - polowałem na kod źródłowy, w którym jest on zaimplementowany i zaktualizuję swoją odpowiedź o te informacje, kiedy ją zbiorę.
Aaron Hall
33

Na stronie 358 książki „ Skrypty Pythona dla obliczeniowej nauki” Hansa Pettera Langtangena wyraźnie stwierdza się, że

  • Te __repr__cele w kompletnej reprezentacji ciąg obiektu;
  • __str__Jest powrót piękny ciąg do drukowania.

Wolę więc rozumieć je jako

  • repr = reprodukcja
  • str = ciąg (reprezentacja)

z punktu widzenia użytkownika, chociaż jest to nieporozumienie, które popełniłem podczas nauki Pythona.

Mały, ale dobry przykład podano również na tej samej stronie w następujący sposób:

Przykład

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
źródło
To jest na str. # 351.
jiten
4
To trochę mylące nazywać reprreprodukcją. Lepiej jest traktować to jako reprezentację.
NelsonGon
31

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

1) __repr__()jest wywoływany, gdy po prostu napiszesz nazwę obiektu na interaktywnej konsoli python i naciśniesz enter.

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

3) W przypadku, gdy go __str__brakuje, należy wydrukować i dowolną funkcję przy użyciu str()wywołań __repr__()obiektu.

4) __str__()kontenerów, gdy zostanie wywołany, wykona __repr__()metodę zawartych w nim elementów.

5) str()wywołanie wewnątrz __str__()może potencjalnie powtórzyć się bez przypadku podstawowego i błąd przy maksymalnej głębokości rekurencji.

6) __repr__()może wywoływać, repr()które spróbuje automatycznie uniknąć nieskończonej rekurencji, zastępując już reprezentowany obiekt na ....

Mangu Singh Rajpurohit
źródło
14

Krótko mówiąc:

__str__służy do pokazania reprezentacji ciągu obiektu, którą mogą odczytać inni.

__repr__służy do wyświetlania znaków reprezentujący w obiekcie.

Powiedzmy, że chcę utworzyć Fractionklasę, w której ciąg reprezentujący ułamek to „(1/2)”, a obiekt (klasa ułamkowa) ma być reprezentowany jako „ułamek (1,2)”

Możemy więc stworzyć prostą klasę frakcji:

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)
Zer0
źródło
13

Szczerze mówiąc, eval(repr(obj))nigdy nie jest używany. Jeśli okaże się, że go używasz, powinieneś przestać, ponieważ evaljest to niebezpieczne, a łańcuchy są bardzo nieefektywnym sposobem serializacji obiektów (użyj picklezamiast tego).

Dlatego polecam ustawienie __repr__ = __str__. Powodem jest to, że str(list)wywołuje reprelementy (uważam to za jedną z największych wad projektowych Pythona, która nie została rozwiązana przez Python 3). Rzeczywista reprprawdopodobnie nie będzie bardzo pomocna jako wynik print [your, objects].

Aby to zakwalifikować, z mojego doświadczenia, najbardziej użytecznym przypadkiem użycia reprfunkcji jest umieszczenie łańcucha wewnątrz innego łańcucha (przy użyciu formatowania łańcucha). W ten sposób nie musisz się martwić o unikanie cudzysłowów lub czegokolwiek. Pamiętaj jednak, że tutaj się nie evaldzieje.

asmeurer
źródło
19
Myślę, że to nie ma sensu. Użycie eval(repr(obj))jest testem rozsądku i praktyczną zasadą - jeśli to poprawnie odtwarza oryginalny obiekt, masz przyzwoitą __repr__implementację. Nie jest tak, że serializujesz obiekty w ten sposób.
jwg
7
evalnie jest z natury niebezpieczny. Nie jest bardziej niebezpieczne niż unlink, openlub pisząc na plikach. Czy powinniśmy przestać zapisywać w plikach, ponieważ być może złośliwy atak mógłby użyć dowolnej ścieżki do pliku, aby wprowadzić do niego zawartość? Wszystko jest niebezpieczne, jeśli głupio z niego korzystają. Idiotyzm jest niebezpieczny. Efekty Dunninga-Krugera są niebezpieczne. evalto tylko funkcja.
Luis Masuelli
12

Z (Nieoficjalnej) Wiki Python Reference (kopia archiwalna) autorstwa effbot:

__str__oblicza„ nieformalną ”reprezentację ciągu obiektu. Różni się __repr__to tym, że nie musi to być prawidłowe wyrażenie w języku Python: zamiast tego można użyć wygodniejszej lub zwięzłej reprezentacji.

Casebash
źródło
3
__repr__nie jest w żaden sposób wymagane do zwrócenia wyrażenia vaild Python.
Mad Physicist,
10

str - Tworzy nowy obiekt ciągu z podanego obiektu.

repr - Zwraca kanoniczną reprezentację ciągu znaków obiektu.

Różnice:

str ():

  • czyni obiekt czytelnym
  • generuje dane wyjściowe dla użytkownika końcowego

repr ():

  • potrzebuje kodu, który odtwarza obiekt
  • generuje dane wyjściowe dla programisty
Inconnu
źródło
8

Jeden aspekt, którego brakuje w innych odpowiedziach. Prawdą jest, że ogólnie wzór jest następujący:

  • Cel __str__: czytelny dla człowieka
  • Cel __repr__: jednoznaczny, możliwy do odczytu maszynowego przezeval

Niestety, to zróżnicowanie jest wadliwe, ponieważ Python REPL, a także IPython używają __repr__do drukowania obiektów w konsoli REPL (zobacz powiązane pytania dotyczące Python i IPython ). Dlatego projekty ukierunkowane na interaktywną pracę konsoli (np. Numpy lub Pandy) zaczęły ignorować powyższe reguły i __repr__zamiast tego zapewnić implementację czytelną dla człowieka .

bluenote10
źródło
7

Z książki Fluent Python :

Podstawowym wymaganiem dla obiektu Python jest zapewnienie użytecznych reprezentacji ciągu, jednego używanego do debugowania i rejestrowania, drugiego do prezentacji użytkownikom końcowym. Właśnie dlatego
specjalne metody __repr__i __str__istnieją w modelu danych.

Ijaz Ahmad Khan
źródło
5

Doskonałe odpowiedzi już obejmują różnicę między __str__i __repr__, co dla mnie sprowadza się do tego, że ten pierwszy jest czytelny nawet dla użytkownika końcowego, a ten drugi jest jak najbardziej użyteczny dla programistów. Biorąc to pod uwagę, uważam, że domyślna implementacja __repr__często nie osiąga tego celu, ponieważ pomija informacje przydatne dla programistów.

Z tego powodu, jeśli mam dość proste __str__, zazwyczaj staram się uzyskać to, co najlepsze z obu światów za pomocą czegoś takiego:

def __repr__(self):
    return '{0} ({1})'.format(object.__repr__(self), str(self))
orome
źródło
4

Należy pamiętać, że pojemnik __str__używa zawartych obiektów ” __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 opowiada się za jednoznacznością nad czytelnością , __str__wywoływaniem tuplewywoływanych obiektów __repr__, „formalną” reprezentacją obiektu. Chociaż formalna reprezentacja jest trudniejsza do odczytania niż nieformalna, jest jednoznaczna i bardziej odporna na błędy.

zangw
źródło
Używa __repr__ gdy nie __str__jest zdefiniowane ( )! Więc się mylisz.
jiten
4

W skrócie:

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
źródło
4
>>> print(decimal.Decimal(23) / decimal.Decimal("1.05"))
21.90476190476190476190476190
>>> decimal.Decimal(23) / decimal.Decimal("1.05")
Decimal('21.90476190476190476190476190')

Po print()wywołaniu decimal.Decimal(23) / decimal.Decimal("1.05")drukowany jest wynik surowego numeru; ten wynik jest w postaci ciągu, który można osiągnąć za pomocą __str__(). Jeśli po prostu wprowadzimy wyrażenie, otrzymamy decimal.Decimalwynik - wynik ten ma postać reprezentacyjną, którą można osiągnąć za pomocą __repr__(). Wszystkie obiekty Python mają dwie formy wyjściowe. Forma łańcucha jest zaprojektowana tak, aby była czytelna dla człowieka. Forma reprezentacyjna jest zaprojektowana do generowania danych wyjściowych, które po dostarczeniu do interpretera Pythona odtworzyłyby (o ile to możliwe) reprezentowany obiekt.

BattleDrum
źródło
4

__str__może być wywołany na obiekcie przez wywołanie str(obj)i powinien zwrócić ciąg czytelny dla człowieka.

__repr__może być wywołany na obiekcie przez wywołanie repr(obj)i powinien zwrócić obiekt wewnętrzny (pola / atrybuty obiektu)

Ten przykład może pomóc:

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
źródło
3

Zrozumieć __str__i __repr__intuicyjnie i trwale odróżnić je w ogóle.

__str__zwraca ciąg ukrytego ciała danego obiektu do odczytu dla oczu
__repr__zwraca rzeczywiste ciało danego obiektu (sam powrót) dla jednoznaczności w identyfikacji.

Zobacz to w przykładzie

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

Co się tyczy __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.

Możemy __repr__wygodnie wykonywać operacje arytmetyczne na wynikach.

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)

jeśli zastosujesz operację na __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'

Zwraca tylko błąd.

Inny przykład.

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

Mam nadzieję, że pomoże to w budowaniu konkretnych podstaw do odkrywania kolejnych odpowiedzi.

Rachunek różniczkowy
źródło
3
  1. __str__musi zwrócić obiekt ciągu, ale __repr__może zwrócić dowolne wyrażenie python.
  2. Jeśli __str__brakuje implementacji, __repr__funkcja jest używana jako rezerwowa. Nie ma rezerwy, jeśli __repr__brakuje implementacji funkcji.
  3. Jeśli __repr__funkcja zwraca ciąg znaków reprezentujący obiekt, możemy pominąć implementację __str__funkcji.

Źródło: https://www.journaldev.com/22460/python-str-repr-functions

Sampath
źródło
2

__repr__jest używany wszędzie, z wyjątkiem metod printi str(gdy __str__zdefiniowano a!)

techkuz
źródło