Jaki jest cel __str__ i __repr__? [duplikować]

83

Naprawdę nie rozumiem, gdzie są __str__i __repr__używane w Pythonie. Mam na myśli, że __str__zwraca reprezentację ciągu obiektu. Ale dlaczego miałbym tego potrzebować? W jakim scenariuszu użycia? Czytałem też o używaniu__repr__

Ale nie rozumiem, gdzie bym ich użył?

Daniel
źródło
4
Dla każdego, kto pochodzi z Rubiego, tl; dr to: __str__= to_si __repr__= inspect.
Ajedi32,
3
Czy to odpowiada na twoje pytanie? Różnica między __str__ a __repr__?
xiaoou wang

Odpowiedzi:

86

__repr__

Wywoływana przez funkcję repr()wbudowaną i konwersję ciągów (cudzysłowy) w celu obliczenia „oficjalnej” reprezentacji obiektu w postaci ciągu. Jeśli to w ogóle możliwe, powinno to wyglądać jak prawidłowe wyrażenie Pythona, którego można by użyć do odtworzenia obiektu o tej samej wartości (w odpowiednim środowisku).

__str__

Wywoływana przez funkcję str()wbudowaną i instrukcję print w celu obliczenia „nieformalnej” reprezentacji obiektu w postaci ciągu.

Użyj, __str__jeśli masz klasę i będziesz potrzebować informacji / nieformalnych danych wyjściowych, ilekroć używasz tego obiektu jako części ciągu. Np. Możesz zdefiniować __str__metody dla modeli Django, które są następnie renderowane w interfejsie administracyjnym Django. Zamiast czegoś takiego <Model object>jak imię i nazwisko osoby, nazwa i data wydarzenia itp.


__repr__i __str__są podobne, w rzeczywistości czasami równe (przykład z BaseSetklasy sets.pyz biblioteki standardowej):

def __repr__(self):
    """Return string representation of a set.

    This looks like 'Set([<list of elements>])'.
    """
    return self._repr()

# __str__ is the same as __repr__
__str__ = __repr__
miku
źródło
1
Dzięki! To jest dokładnie to, czego szukałem!
Daniel
co robi `return self._repr ()`, kiedy uruchamiam kod i próbuję go zrozumieć, powiedzmy, że __repr __ () przyjmuje dokładnie jeden argument.
świeci
Czy mogę więc używać __repr__zamiast __str__django?
Amit Tripathi
61

Jedynym miejscem, w którym często używasz ich obu, jest sesja interaktywna. Jeśli wydrukujesz obiekt __str__, zostanie wywołana jego metoda, podczas gdy jeśli użyjesz samego obiektu, __repr__zostanie wyświetlony:

>>> from decimal import Decimal
>>> a = Decimal(1.25)
>>> print(a)
1.25                  <---- this is from __str__
>>> a
Decimal('1.25')       <---- this is from __repr__

Ma __str__być jak najbardziej czytelny dla człowieka, podczas gdy __repr__celem powinno być coś, co można wykorzystać do odtworzenia obiektu, chociaż często nie będzie dokładnie tak, jak został stworzony, jak w tym przypadku.

Nie jest też niczym niezwykłym w przypadku obu __str__i __repr__zwracania tej samej wartości (na pewno w przypadku typów wbudowanych).

Scott Griffiths
źródło
Dzięki za przykład, lepiej zrozumiałem, gdzie jest to używane domyślnie
JayRizzo,
17

Konik polny, jeśli masz wątpliwości, idź na górę i przeczytaj starożytne teksty . W nich znajdziesz, że __repr __ () powinien:

Jeśli to w ogóle możliwe, powinno to wyglądać jak prawidłowe wyrażenie Pythona, którego można by użyć do odtworzenia obiektu o tej samej wartości.

Peter Rowell
źródło
6
-1, ponieważ to nawet nie próbuje odpowiedzieć na rzeczywiste pytanie, czyli jakie są przypadki użycia.
Scott Griffiths,
4
@Scott: Masz rację. Ale z drugiej strony, faktyczne pytanie nie wykazało absolutnie żadnej próby przechodzenia do głównych dokumentów w pierwszej kolejności. Jedną rzeczą jest zadanie pytania, które pokazuje, że próbowałeś odpowiedzieć sobie na nie sam, ale nadal jesteś trochę zdezorientowany co do jakiegoś aspektu, a zupełnie inną rzeczą jest zadawanie takiego pytania. Samo wpisanie jego tematu, ponieważ nowe pytanie pokazuje, że 5 z 6 najczęściej sugerowanych wątków SO odpowiedziałoby na jego pytanie, ale nie przeszkadzało mu to. Nie do końca udzieliłem mu jasnej odpowiedzi, ale bardzo mnie to kusiło.
Peter Rowell,
1
Właściwie powiedział, że czytał o tym __repr__, że oficjalna dokumentacja tak naprawdę nie odpowiada na pytanie, dlaczego go używasz, a tylko dlatego, że odpowiedź na pytanie jest gdzie indziej, nie jest dobrym powodem, aby tego również nie było odpowiedź na SO (tak często, jak nie Google, sprowadzi cię tu z powrotem!) Jeśli nie uważasz, że pytanie jest warte odpowiedzi, nie możesz po prostu na nie odpowiedzieć, chociaż w tym przypadku zgadzam się, że jest już dobrze omówiony Tak więc powiązanie z duplikatami byłoby właściwą odpowiedzią.
Scott Griffiths
Właściwie to się mylisz. Dokumentacja wyraźnie mówi, dlaczego miałbyś go używać, na przykład: „Jest to zwykle używane do debugowania, więc ważne jest, aby reprezentacja była bogata w informacje i jednoznaczna”. Widziałem, jak wiele forów (fora?) Tonęło pod ciężarem Help Vampires i bolało mnie, gdy zaczęło się to zdarzać. Jeśli chodzi o łączenie się z innymi oczywistymi odpowiedziami SO, to właśnie taki jest cel mechanizmu sugestii, który uruchamia się, gdy wpisujesz wiersz tematu, ale zdecydował się zignorować wszystkie sugestie. QED i PDQ też.
Peter Rowell,
5
Cóż, dokumentacja nadal nie mówi, jak używać tego do debugowania, ale naprawdę nie zamierzałem wdawać się w kłótnię na ten temat. Przynajmniej zgadzamy się, że twoja odpowiedź nie odpowiadała na pytanie, więc moje -1 nadal wydaje mi się uzasadnione. Jeśli pytanie jest źle napisane / jest duplikatem / trywialne, możesz pomóc ulepszyć pytanie, utworzyć link do duplikatów lub po prostu zagłosować na pytanie. Myślę, że moim głównym zarzutem jest to, że odpowiedzi powinny próbować odpowiedzieć na pytanie - istnieją inne mechanizmy krytyki tego pytania. Zamknę się teraz, bo myślę, że oboje mamy tu lepsze rzeczy do roboty.
Scott Griffiths,
14

Opierając się na poprzednich odpowiedziach i pokazując więcej przykładów. Przy prawidłowym użyciu różnica między stri reprjest wyraźna. W skrócie reprnależy zwrócić ciąg znaków, który może być wklejony do kopiowania przebudowany dokładny stan obiektu, natomiast strjest przydatny do loggingi observingdebugowanie wyników. Oto kilka przykładów pokazujących różne wyniki dla niektórych znanych bibliotek.

Datetime

print repr(datetime.now())    #datetime.datetime(2017, 12, 12, 18, 49, 27, 134411)
print str(datetime.now())     #2017-12-12 18:49:27.134452

Dobrze strjest wydrukować do pliku dziennika, gdzie reprmożna go zmienić, jeśli chcesz go uruchomić bezpośrednio lub zrzucić jako polecenia do pliku.

x = datetime.datetime(2017, 12, 12, 18, 49, 27, 134411)

Odrętwiały

print repr(np.array([1,2,3,4,5])) #array([1, 2, 3, 4, 5])
print str(np.array([1,2,3,4,5]))  #[1 2 3 4 5]

w Numpy reprjest ponownie bezpośrednio zużywalny.

Przykład niestandardowego Vector3

class Vector3(object):
    def __init__(self, args):
        self.x = args[0]
        self.y = args[1]
        self.z = args[2]

    def __str__(self):
        return "x: {0}, y: {1}, z: {2}".format(self.x, self.y, self.z)

    def __repr__(self):
        return "Vector3([{0},{1},{2}])".format(self.x, self.y, self.z)

W tym przykładzie reprzwraca ponownie ciąg, który może być bezpośrednio używany / wykonywany, ale strjest bardziej przydatny jako wyjście debugowania.

v = Vector3([1,2,3])
print str(v)     #x: 1, y: 2, z: 3
print repr(v)    #Vector3([1,2,3])

Jedną z rzeczy, o których warto pamiętać, jeśli strnie jest określona, ale repr, strautomatycznie zadzwoni repr. Dlatego zawsze dobrze jest przynajmniej zdefiniowaćrepr

user1767754
źródło
5

Miejmy klasę bez __str__funkcji.

class Employee:

    def __init__(self, first, last, pay):
        self.first = first 
        self.last = last
        self.pay = pay

emp1 = Employee('Ivan', 'Smith', 90000)

print(emp1)

Kiedy drukujemy to wystąpienie klasy, emp1otrzymujemy:

<__main__.Employee object at 0x7ff6fc0a0e48>

Nie jest to zbyt pomocne, a na pewno nie jest to, co chcemy wydrukować, jeśli używamy go do wyświetlania (jak w html)

Więc teraz ta sama klasa, ale z __str__funkcją:

class Employee:

    def __init__(self, first, last, pay):
        self.first = first 
        self.last = last
        self.pay = pay

    def __str__(self):
        return(f"The employee {self.first} {self.last} earns {self.pay}.")
        # you can edit this and use any attributes of the class

emp2 = Employee('John', 'Williams', 90000)

print(emp2)

Teraz zamiast wypisywać, że istnieje obiekt, otrzymujemy to, co określiliśmy zwracając __str__funkcję:

The employee John Williams earns 90000

Zorana
źródło
3

strbędzie miał nieformalny i czytelny format, a jednocześnie reprzapewni oficjalną reprezentację obiektu.

class Complex:
    # Constructor
    def __init__(self, real, imag):
        self.real = real
        self.imag = imag

    # "official" string representation of an object
    def __repr__(self):
        return 'Rational(%s, %s)' % (self.real, self.imag)

    # "informal" string representation of an object (readable)
    def __str__(self):
        return '%s + i%s' % (self.real, self.imag)

    t = Complex(10, 20)

    print (t)     # this is usual way we print the object
    print (str(t))  # this is str representation of object 
    print (repr(t))  # this is repr representation of object   

Answers : 

Rational(10, 20) # usual representation
10 + i20      # str representation
Rational(10, 20)  # repr representation
Vishvajit Pathak
źródło
1

str i repr są sposobami reprezentacji. Możesz ich używać podczas pisania zajęć.

class Fraction:
def __init__(self, n, d):
    self.n = n
    self.d = d
def __repr__(self):
    return "{}/{}".format(self.n, self.d)

na przykład kiedy drukuję jej egzemplarz, zwraca rzeczy.

print(Fraction(1, 2))

prowadzi do

1/2

podczas

class Fraction:
def __init__(self, n, d):
    self.n = n
    self.d = d
def __str__(self):
    return "{}/{}".format(self.n, self.d)
print(Fraction(1, 2))

skutkuje również

1/2

Ale co, jeśli napiszesz oba z nich, z których korzysta Python?

class Fraction:
def __init__(self, n, d):
    self.n = n
    self.d = d
def __str__(self):
    return "str"
def __repr__(self):
    return "repr"

print(Fraction(None, None))

To skutkuje

str

Więc python w rzeczywistości używa metody str , a nie metody repr , gdy oba są zapisywane.

KingWitherBrine
źródło
0

Załóżmy, że masz klasę i chcesz sprawdzić instancję, a wydruk nie zawiera zbyt wielu przydatnych informacji

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age


p1 = Person("John", 36)
print(p1)  # <__main__.Animal object at 0x7f9060250410>

Teraz zobacz klasę ze str , która pokazuje informacje o instancji, a przy repr nawet nie potrzebujesz print. Nieźle, nie?

class Animal:
    def __init__(self, color, age, breed):
        self.color = color
        self.age = age
        self.breed = breed

    def __str__(self):
        return f"{self.color} {self.breed} of age {self.age}"

    def __repr__(self):
        return f"repr : {self.color} {self.breed} of age {self.age}"


a1 = Animal("Red", 36, "Dog")
a1  # repr : Red Dog of age 36
print(a1)  # Red Dog of age 36
xiaoou wang
źródło