Vraag Verschil tussen __str__ en __repr__?


Wat is het verschil tussen __str__ en __repr__ in Python?


2107
2017-09-17 04:27


oorsprong


antwoorden:


Alex samengevat, maar verrassend genoeg was het te beknopt.

Allereerst wil ik de hoofdpunten herhalen Alex's bericht:

  • De standaardimplementatie is nutteloos (het is moeilijk om er een te bedenken die dat niet zou zijn, maar ja)
  • __repr__ doel is om ondubbelzinnig te zijn
  • __str__ doel is om leesbaar te zijn
  • container __str__ maakt gebruik van ingesloten objecten ' __repr__

Standaard implementatie is nutteloos

Dit is meestal een verrassing, omdat de standaardwaarden van Python vrij nuttig zijn. In dit geval echter een standaardwaarde voor __repr__ welke zou handelen als:

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

zou te gevaarlijk zijn geweest (bijvoorbeeld, te gemakkelijk om in oneindige recursie te komen als objecten naar elkaar verwijzen). Dus komt Python eruit. Merk op dat er één standaard is die waar is: if __repr__ is gedefinieerd, en __str__ niet, het object zal zich gedragen alsof __str__=__repr__.

Dit betekent in eenvoudige bewoordingen: bijna elk object dat u implementeert, moet functioneel zijn __repr__ dat is bruikbaar om het object te begrijpen. Implementeren __str__ is optioneel: doe dat als u een "mooie afdruk" -functionaliteit nodig hebt (bijvoorbeeld gebruikt door een rapportengenerator).

Het doel van __repr__ moet ondubbelzinnig zijn

Laat me het zeggen - ik geloof niet in debuggers. Ik weet niet echt hoe ik een foutopsporingsprogramma moet gebruiken en heb er nooit een serieus gebruikt. Verder geloof ik dat de grote fout in debuggers hun basale karakter is - de meeste mislukkingen die ik heb geprobeerd, gebeurden lang geleden in een heel ver weg gelegen melkwegstelsel. Dit betekent dat ik, met religieuze vurigheid, geloof in het loggen. Logging is het levensbloed van elk fatsoenlijk brand-en-vergeet server-systeem. Python maakt het gemakkelijk om te loggen: met misschien een aantal projectspecifieke wrappers, alles wat je nodig hebt is een

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)

Maar je moet de laatste stap doen - zorg ervoor dat elk object dat je implementeert een nuttige reproductie heeft, dus zo'n code kan gewoon werken. Dit is de reden waarom het "eval" ding opkomt: als je genoeg informatie hebt eval(repr(c))==c, dat betekent dat je alles weet wat er te weten valt c. Als dat gemakkelijk genoeg is, doe het dan tenminste op een fuzzy manier. Als dat niet het geval is, zorg dan dat u voldoende informatie over hebt c hoe dan ook. Ik gebruik meestal een eval-achtig formaat: "MyClass(this=%r,that=%r)" % (self.this,self.that). Dit betekent niet dat u MyClass daadwerkelijk kunt bouwen, of dat dit de juiste constructorargumenten zijn - maar het is een nuttige vorm om uit te drukken "dit is alles wat u moet weten over deze instantie".

Opmerking: ik heb gebruikt %r hierboven, niet %s. Je wilt altijd gebruiken repr() [of %r formatting character, equivalent] inside __repr__ implementatie, of je verslaat het doel van repr. U wilt kunnen differentiëren MyClass(3) en MyClass("3").

Het doel van __str__ moet leesbaar zijn

In het bijzonder is het niet bedoeld om ondubbelzinnig te zijn - let op dat str(3)==str("3"). Evenzo, als je een IP-abstractie implementeert, is het prima als je de str lijkt op 192.168.1.1. Bij het implementeren van een datum / tijd abstractie, kan de str worden "2010/4/12 15:35:22", enz. Het doel is om het te vertegenwoordigen op een manier dat een gebruiker, niet een programmeur, zou willen lezen. Hak nutteloze cijfers af, doe alsof je een andere klasse bent - zolang het de leesbaarheid ondersteunt, is het een verbetering.

container __str__ maakt gebruik van ingesloten objecten ' __repr__

Dit lijkt verrassend, nietwaar? Het is een beetje, maar hoe leesbaar zou dat zijn

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

worden? Niet erg. Met name de tekenreeksen in een container vinden het veel te gemakkelijk om de tekenreeksrepresentatie te verstoren. Bedenk dat, ondanks onduidelijkheid, Python de verleiding om te raden weerstaat. Als u het bovenstaande gedrag wilt wanneer u een lijst afdrukt, gewoon

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

(u kunt waarschijnlijk ook achterhalen wat u met woordenboeken moet doen.

Overzicht

uitvoeren __repr__ voor elke klasse die je implementeert. Dit zou een tweede natuur moeten zijn. uitvoeren __str__ als je denkt dat het handig zou zijn om een ​​stringversie te hebben die ten koste gaat van meer leesbaarheid ten gunste van meer dubbelzinnigheid.


2171
2018-04-13 00:56



Mijn vuistregel: __repr__ is voor ontwikkelaars, __str__ is voor klanten.


369
2017-09-17 11:35



Tenzij u specifiek iets anders doet, hebben de meeste klassen geen nuttige resultaten voor:

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

Zoals je ziet - geen verschil en geen informatie die verder gaat dan de klasse en het object id. Als je alleen één van de twee overschrijft ...:

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

zoals je ziet, als je opheft __repr__, dat is OOK gebruikt voor __str__, maar niet andersom.

Andere belangrijke weetjes om te weten: __str__ op een ingebouwde container gebruikt de __repr__, Niet de __str__, voor de items die het bevat. En, ondanks de woorden over het onderwerp die in typische documenten worden gevonden, ondervindt bijna niemand het maken van de __repr__ van objecten een tekenreeks zijn eval kan gebruiken om een ​​gelijk object te bouwen (het is gewoon te moeilijk, EN niet wetende hoe de relevante module daadwerkelijk werd geïmporteerd, maakt het eigenlijk helemaal onmogelijk).

Dus, mijn advies: focus op maken __str__ redelijk leesbaar voor mensen, en __repr__ zo ondubbelzinnig als je maar kunt, zelfs als dat het fuzzy onbereikbare doel van het maken verstoort __repr__De geretourneerde waarde is acceptabel als invoer voor __eval__!


319
2017-09-17 04:49



__repr__: representatie van python-object meestal eval zal het terug naar dat object converteren

__str__: is wat je denkt dat object in tekstvorm is

bijv.

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



Kortom, het doel van __repr__ is ondubbelzinnig en __str__ zal zo zijn   leesbaar.

Hier is een goed voorbeeld:

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

Lees deze documentatie voor repr:

repr(object)

Retourneer een tekenreeks met een afdrukbare weergave van een object. Dit is dezelfde waarde die wordt gegenereerd door conversies (omgekeerd   citaten). Het is soms handig om toegang te hebben tot deze bewerking als   een gewone functie. Voor veel typen doet deze functie een poging   om een ​​tekenreeks te retourneren die een object oplevert met dezelfde waarde wanneer   doorgegeven aan eval(), anders is de weergave een string ingesloten   punthaken die de naam van het type object bevatten   samen met aanvullende informatie vaak inclusief de naam en   adres van het object. Een klasse kan bepalen wat deze functie retourneert   voor zijn instanties door een te definiëren __repr__() methode.

Hier is de documentatie voor str:

str(object='')

Retourneer een tekenreeks met een mooie afdrukbaar   weergave van een object. Voor tekenreeksen retourneert dit de reeks   zelf. Het verschil met repr(object)is dat str(object) doet niet   probeer altijd een tekenreeks terug te geven die acceptabel is eval(); haar   doel is om een ​​afdrukbare reeks terug te sturen. Als er geen argument wordt gegeven, retourneert   de lege string, ''.


114
2017-10-25 18:38



Wat is het verschil tussen __str__ en __repr__ in Python?

__str__ (lees als "dunder (double-underscore) string") en __repr__ (lees als "dunder-repper" (voor "representatie")) zijn beide speciale methoden die tekenreeksen retourneren op basis van de staat van het object.

__repr__ biedt back-upgedrag als __str__ ontbreekt.

Dus je moet eerst een a schrijven __repr__ Hiermee kunt u een equivalent object opnieuw instellen op basis van de tekenreeks die het retourneert, bijvoorbeeld gebruik makend van eval of door het in karakter-voor-teken in een Python-shell te typen.

Op elk moment later, kan men een schrijven __str__ voor een door de gebruiker leesbare tekenreeksrepresentatie van de instantie, wanneer iemand gelooft dat dit noodzakelijk is.

__str__

Als u een object afdrukt of doorgeeft aan format, str.formatof str, dan als een __str__ methode is gedefinieerd, die methode zal worden aangeroepen, anders __repr__ zal gebruikt worden.

__repr__

De __repr__ methode wordt aangeroepen door de ingebouwde functie repr en is wat er op je python-shell wordt herhaald als het een expressie evalueert die een object retourneert.

Omdat het een back-up voor biedt __str__, als je er maar een kunt schrijven, begin dan met __repr__

Hier is de ingebouwde hulp voor repr:

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

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

Dat wil zeggen, voor de meeste objecten, als u typt in wat er wordt afgedrukt repr, je zou in staat moeten zijn om een ​​equivalent object te maken. Maar dit is niet de standaardimplementatie.

Standaard implementatie van __repr__

Het standaard object __repr__ is (C Python-bron) zoiets als:

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

Dat betekent standaard dat u de module waaruit het object afkomstig is, de klassenaam en de hexadecimale weergave van de locatie in het geheugen afdrukt, bijvoorbeeld:

<__main__.Foo object at 0x7f80665abdd0>

Deze informatie is niet erg nuttig, maar er is geen manier om af te leiden hoe iemand nauwkeurig een canonieke weergave van een gegeven instantie kan maken, en het is beter dan niets, ons in ieder geval te vertellen hoe we het uniek in het geheugen kunnen identificeren.

Hoe kan __repr__ wees nuttig?

Laten we eens kijken naar hoe nuttig het kan zijn, met behulp van de Python-shell en datetime voorwerpen. Eerst moeten we het importeren datetime module:

import datetime

Als we bellen datetime.now in de shell zien we alles wat we nodig hebben om een ​​equivalent datetime-object opnieuw te maken. Dit wordt gemaakt door de datetime __repr__:

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

Als we een datetime-object afdrukken, zien we een aardig menselijk leesbaar (in feite, ISO) formaat. Dit wordt geïmplementeerd door datetime's __str__:

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

Het is een eenvoudige zaak om het object dat we verloren hebben opnieuw te creëren omdat we het niet aan een variabele hebben toegewezen door het te kopiëren en te plakken vanuit de __repr__ uitvoeren en vervolgens afdrukken en we krijgen het in dezelfde leesbare uitvoer als het andere object:

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

Hoe implementeer ik ze?

Terwijl je aan het ontwikkelen bent, wil je indien mogelijk objecten in dezelfde staat kunnen reproduceren. Dit is bijvoorbeeld hoe het datetime-object definieert __repr__ (Python-bron). Het is vrij complex, vanwege alle attributen die nodig zijn om een ​​dergelijk object te reproduceren:

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

Als u wilt dat uw object een meer leesbare menselijke voorstelling heeft, kunt u het implementeren __str__ volgende. Hier is hoe het datetime-object (Python-bron) werkt __str__, wat gemakkelijk is omdat het al een functie heeft om het in ISO-formaat weer te geven:

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

set __repr__ = __str__?

Dit is een kritiek op een ander antwoord hier dat suggereert om te zetten __repr__ = __str__.

omgeving __repr__ = __str__ is dom - __repr__ is een terugval voor __str__ en een __repr__, geschreven voor gebruik door ontwikkelaars bij het debuggen, moet worden geschreven voordat je een a schrijft __str__.

Je hebt een nodig __str__ alleen als u een tekstuele weergave van het object nodig hebt.

Conclusie

Bepalen __repr__ voor objecten die u schrijft, zodat u en andere ontwikkelaars een reproduceerbaar voorbeeld hebben wanneer u het gebruikt terwijl u zich ontwikkelt. Bepalen __str__ wanneer je een door mensen leesbare tekenreeksrepresentatie nodig hebt.


84
2018-01-25 02:01



Afgezien van alle gegeven antwoorden, zou ik enkele punten willen toevoegen:

1) __repr__() wordt aangeroepen als u de naam van het object op de interactieve python-console schrijft en op enter drukt.

2) __str__() wordt aangeroepen wanneer u een object gebruikt met een afdrukinstructie.

3) In het geval, als __str__ ontbreekt, print dan en elke functie die gebruikt str() oproept __repr__() van het object.

4) __str__() van containers, wanneer aangeroepen zal worden uitgevoerd __repr__() methode van zijn ingesloten elementen.

5) str() binnen geroepen __str__() kan mogelijk recursureren zonder een basisscenario, en een fout in de maximale recursiediepte.

6) __repr__() kan bellen repr() die zal proberen om oneindige recursie automatisch te vermijden, waarbij een reeds voorgesteld object wordt vervangen door ....


12
2017-09-08 03:27



In alle eerlijkheid, eval(repr(obj)) wordt nooit gebruikt. Als u merkt dat u het gebruikt, moet u stoppen, want eval is gevaarlijk en strings zijn een zeer inefficiënte manier om je objecten te serialiseren (gebruik pickle in plaats daarvan).

Daarom zou ik het instellen aanbevelen __repr__ = __str__. De reden is dat str(list) calls repr op de elementen (ik beschouw dit als een van de grootste ontwerpfouten van Python die niet is behandeld door Python 3). Een feitelijk repr zal waarschijnlijk niet erg nuttig zijn als de uitvoer van print [your, objects].

Om dit, naar mijn ervaring, te kwalificeren, het meest bruikbare gebruik van de repr functie is om een ​​string in een andere string te plaatsen (met behulp van string-opmaak). Op deze manier hoeft u zich geen zorgen te maken over ontsnappende offertes of iets anders. Maar merk op dat er geen is eval hier gebeurt.


11
2017-11-15 10:39



Simpel gezegd:

__str__ wordt gebruikt om een ​​tekenreeksrepresentatie van uw object weer te geven gemakkelijk te lezen door anderen.

__repr__ wordt gebruikt om een ​​tekenreeksrepresentatie van weer te geven de voorwerp.

Laten we zeggen dat ik een wil maken Fraction klasse waarbij de tekenreeksrepresentatie van een breuk '(1/2)' is en het object (breukklasse) moet worden weergegeven als 'Breuk (1,2)'

Dus we kunnen een eenvoudige breukklasse maken:

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)

10
2018-01-12 02:53