Odpowiedzi:
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 :
__repr__
celem jest być jednoznacznym__str__
celem jest być czytelnym__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 %r
powyżej, nie %s
. Zawsze chcesz użyć repr()
[lub %r
formatowania 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.
__repr__
że potrzebowałem do debugowania. Dziękuję za pomoc
Moja ogólna zasada: __repr__
jest dla programistów, __str__
jest dla klientów.
__str__
więc normalni programiści mają czytelny obiekt. Z drugiej strony __repr__
jest dla samych programistów SDK.
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 eval
moż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__
!
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.
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.
__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__
.
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 A
jest objęty zakresem - więc prawdopodobnie nie jest bardzo przydatny.
str
element użycia kontenera, repr
ponieważ [1, 2, 3]
! = ["1", "2, 3"]
.
__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
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 akceptowalnyeval()
; jego celem jest zwrócenie drukowalnego ciągu. Jeżeli nie podano żadnych argumentów, zwraca pusty ciąg,''
.
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 eval
lub 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.format
lub 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 repr
i 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.
__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.
__repr__
być przydatny?Zobaczmy, jak może być użyteczne, używając powłoki i datetime
obiektów Pythona . Najpierw musimy zaimportować datetime
moduł:
import datetime
Jeśli wywołamy datetime.now
powł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
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=' ')
__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.
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.
type(obj).__qualname__
?
Na stronie 358 książki „ Skrypty Pythona dla obliczeniowej nauki” Hansa Pettera Langtangena wyraźnie stwierdza się, że
__repr__
cele w kompletnej reprezentacji ciąg obiektu;__str__
Jest powrót piękny ciąg do drukowania.Wolę więc rozumieć je jako
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:
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'
repr
reprodukcją. Lepiej jest traktować to jako reprezentację.
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 ...
.
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ć Fraction
klasę, 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)
Szczerze mówiąc, eval(repr(obj))
nigdy nie jest używany. Jeśli okaże się, że go używasz, powinieneś przestać, ponieważ eval
jest to niebezpieczne, a łańcuchy są bardzo nieefektywnym sposobem serializacji obiektów (użyj pickle
zamiast tego).
Dlatego polecam ustawienie __repr__ = __str__
. Powodem jest to, że str(list)
wywołuje repr
elementy (uważam to za jedną z największych wad projektowych Pythona, która nie została rozwiązana przez Python 3). Rzeczywista repr
prawdopodobnie nie będzie bardzo pomocna jako wynik print [your, objects]
.
Aby to zakwalifikować, z mojego doświadczenia, najbardziej użytecznym przypadkiem użycia repr
funkcji 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 eval
dzieje.
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.
eval
nie jest z natury niebezpieczny. Nie jest bardziej niebezpieczne niż unlink
, open
lub 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. eval
to tylko funkcja.
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. ”
__repr__
nie jest w żaden sposób wymagane do zwrócenia wyrażenia vaild Python.
str
- Tworzy nowy obiekt ciągu z podanego obiektu.
repr
- Zwraca kanoniczną reprezentację ciągu znaków obiektu.
Różnice:
str ():
repr ():
Jeden aspekt, którego brakuje w innych odpowiedziach. Prawdą jest, że ogólnie wzór jest następujący:
__str__
: czytelny dla człowieka__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 .
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.
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))
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 tuple
wywoływanych obiektów __repr__
, „formalną” reprezentacją obiektu. Chociaż formalna reprezentacja jest trudniejsza do odczytania niż nieformalna, jest jednoznaczna i bardziej odporna na błędy.
__repr__
gdy nie __str__
jest zdefiniowane ( )! Więc się mylisz.
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'
>>> 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.Decimal
wynik - 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.
__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
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.
__str__
musi zwrócić obiekt ciągu, ale __repr__
może zwrócić dowolne wyrażenie python.__str__
brakuje implementacji, __repr__
funkcja jest używana jako rezerwowa. Nie ma rezerwy, jeśli __repr__
brakuje implementacji funkcji.__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