Question Différence entre __str__ et __repr__?


Quelle est la différence entre __str__ et __repr__ dans Python?


2107
2017-09-17 04:27


origine


Réponses:


Alex résumé bien mais, étonnamment, était trop succinct.

Tout d'abord, permettez-moi de réitérer les principaux points Le message d'Alex:

  • L'implémentation par défaut est inutile (il est difficile d'en imaginer une qui ne le serait pas, mais oui)
  • __repr__ le but est d'être sans ambiguïté
  • __str__ le but est d'être lisible
  • Conteneur __str__ utilise des objets contenus ' __repr__

La mise en œuvre par défaut est inutile

C'est surtout une surprise car les valeurs par défaut de Python ont tendance à être assez utiles. Cependant, dans ce cas, avoir un défaut pour __repr__ qui agirait comme:

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

aurait été trop dangereux (par exemple, trop facile d'entrer dans la récurrence infinie si les objets se réfèrent les uns aux autres). Alors Python se débrouille. Notez qu'il y a un défaut qui est vrai: si __repr__ est défini, et __str__ n'est pas, l'objet se comportera comme si __str__=__repr__.

Cela signifie, en termes simples: presque tous les objets que vous implémentez doivent avoir une fonctionnalité __repr__ c'est utilisable pour comprendre l'objet. Exécution __str__ est optionnel: faites-le si vous avez besoin d'une fonctionnalité "joli print" (par exemple, utilisée par un générateur de rapport).

L'objectif de __repr__ est d'être sans ambiguïté

Laissez-moi sortir et dire - je ne crois pas aux débogueurs. Je ne sais pas vraiment comment utiliser un débogueur, et je n'en ai jamais utilisé sérieusement. En outre, je crois que la grande faille dans les débogueurs est leur nature fondamentale - la plupart des échecs que j'ai débugués se sont produits il y a très longtemps, dans une galaxie très lointaine. Cela signifie que je crois, avec ferveur religieuse, dans l'exploitation forestière. La journalisation est la pierre angulaire de tout système serveur fire-and-forget décent. Python facilite la connexion: avec peut-être des wrappers spécifiques au projet, tout ce dont vous avez besoin est un

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)

Mais vous devez faire la dernière étape - assurez-vous que chaque objet que vous implémentez a une utilité, donc un code comme celui-ci peut fonctionner. C'est pourquoi la chose "eval" arrive: si vous avez assez d'informations eval(repr(c))==c, cela signifie que vous savez tout ce qu'il faut savoir sur c. Si c'est assez facile, au moins d'une manière floue, faites-le. Si non, assurez-vous d'avoir suffisamment d'informations sur c en tous cas. J'utilise généralement un format semblable à eval: "MyClass(this=%r,that=%r)" % (self.this,self.that). Cela ne signifie pas que vous pouvez réellement construire MyClass, ou que ce sont les bons arguments constructeur - mais c'est une forme utile pour exprimer "c'est tout ce que vous devez savoir sur cette instance".

Note: j'ai utilisé %r ci-dessus, pas %s. Vous voulez toujours utiliser repr() [ou %r caractère de mise en forme, de manière équivalente] à l'intérieur __repr__ mise en œuvre, ou vous êtes en train de battre l'objectif de repr. Vous voulez être capable de différencier MyClass(3) et MyClass("3").

L'objectif de __str__ doit être lisible

Plus précisément, il n'est pas destiné à être sans ambiguïté - notez que str(3)==str("3"). De même, si vous implémentez une abstraction IP, avoir la str de ressembler à 192.168.1.1 est très bien. Lors de la mise en œuvre d'une abstraction date / heure, le str peut être "2010/4/12 15:35:22", etc. Le but est de le représenter de manière à ce qu'un utilisateur, et non un programmeur, veuille le lire. Couper les chiffres inutiles, prétendre être une autre classe - tant que cela prend en charge la lisibilité, c'est une amélioration.

Conteneur __str__ utilise des objets contenus ' __repr__

Cela semble surprenant, n'est-ce pas? C'est un peu, mais comment serait lisible

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

être? Pas très. Plus précisément, les chaînes d'un conteneur trouveraient trop facile de perturber sa représentation sous forme de chaîne. Face à l'ambiguïté, rappelez-vous, Python résiste à la tentation de deviner. Si vous voulez le comportement ci-dessus lorsque vous imprimez une liste, juste

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

(Vous pouvez probablement aussi savoir quoi faire à propos des dictionnaires.

Résumé

Mettre en place __repr__ pour toute classe que vous implémentez. Cela devrait être une seconde nature. Mettre en place __str__ Si vous pensez qu'il serait utile d'avoir une version de chaîne qui se trompe du côté de plus de lisibilité en faveur de plus d'ambiguïté.


2171
2018-04-13 00:56



Ma règle générale: __repr__ est pour les développeurs, __str__ est pour les clients.


369
2017-09-17 11:35



À moins que vous agissiez spécifiquement pour assurer le contraire, la plupart des classes n'ont pas de résultats utiles pour:

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

Comme vous voyez - aucune différence, et aucune information au-delà de la classe et de l'objet id. Si vous ne remplacez que l'un des deux ...:

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

comme vous le voyez, si vous remplacez __repr__, c'est AUSSI utilisé pour __str__, mais pas vice versa.

D'autres informations cruciales à connaître: __str__ sur un conteneur intégré utilise le __repr__, Pas le __str__, pour les articles qu'il contient. Et, malgré les mots sur le sujet trouvés dans les documents typiques, presque personne ne dérange faire le __repr__ des objets soit une chaîne qui eval peut utiliser pour construire un objet égal (c'est juste trop dur, et ne pas savoir comment le module correspondant a été importé le rend réellement impossible).

Donc, mon conseil: se concentrer sur la fabrication __str__ raisonnablement lisible par l'homme, et __repr__ aussi clair que possible, même si cela interfère avec l'objectif flou inaccessible de faire __repr__La valeur retournée est acceptable comme entrée pour __eval__!


319
2017-09-17 04:49



__repr__: la représentation de l'objet python habituellement eval le convertira en cet objet

__str__: est ce que vous pensez est cet objet sous forme de texte

par exemple.

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



En bref, l'objectif de __repr__ est d'être sans ambiguïté et __str__ est d'être   lisible.

Voici un bon exemple:

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

Lisez cette documentation pour repr:

repr(object)

Renvoie une chaîne contenant une représentation imprimable d'un objet. C'est la même valeur que celle générée par les conversions   citations). Il est parfois utile de pouvoir accéder à cette opération   une fonction ordinaire. Pour de nombreux types, cette fonction tente   renvoyer une chaîne qui donnerait un objet avec la même valeur lorsque   transmis à eval(), sinon la représentation est une chaîne de caractères   chevrons qui contient le nom du type de l'objet   avec des informations supplémentaires, y compris souvent le nom et   adresse de l'objet. Une classe peut contrôler ce que retourne cette fonction   pour ses instances en définissant un __repr__() méthode.

Voici la documentation pour str:

str(object='')

Renvoie une chaîne contenant un joli texte imprimable   représentation d'un objet. Pour les chaînes, cela renvoie la chaîne   lui-même. La différence avec repr(object)est-ce str(object) ne fait pas   toujours tenter de renvoyer une chaîne acceptable pour eval(); ses   L'objectif est de renvoyer une chaîne imprimable. Si aucun argument n'est donné, renvoie   la chaîne vide, ''.


114
2017-10-25 18:38



Quelle est la différence entre __str__ et __repr__ en Python?

__str__ (lire "string dunder (double-underscore)") et __repr__ (lire "dunder-repper" (pour "représentation")) sont deux méthodes spéciales qui retournent des chaînes basées sur l'état de l'objet.

__repr__ fournit un comportement de sauvegarde si __str__ est manquant.

Donc, il faut d'abord écrire un __repr__ Cela vous permet de réinstituer un objet équivalent à partir de la chaîne renvoyée, par ex. en utilisant eval ou en le tapant dans un caractère-pour-caractère dans un shell Python.

À tout moment plus tard, on peut écrire un __str__ pour une représentation sous forme de chaîne de caractères de l'instance lisible par l'utilisateur, lorsque cela est nécessaire.

__str__

Si vous imprimez un objet ou le transmettez à format, str.format, ou str, alors si un __str__ méthode est définie, cette méthode sera appelée, sinon, __repr__ sera utilisé.

__repr__

le __repr__ méthode est appelée par la fonction intégrée repr et est ce qui est répercuté sur votre shell python quand il évalue une expression qui renvoie un objet.

Comme il fournit une sauvegarde pour __str__, si vous ne pouvez en écrire qu'une, commencez par __repr__

Voici l'aide intégrée sur repr:

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

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

C'est-à-dire, pour la plupart des objets, si vous tapez ce qui est imprimé par repr, vous devriez être capable de créer un objet équivalent. Mais ce n'est pas l'implémentation par défaut.

Implémentation par défaut de __repr__

L'objet par défaut __repr__ est (Source C Python) quelque chose comme:

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

Cela signifie que vous imprimez par défaut le module dont provient l'objet, le nom de la classe et la représentation hexadécimale de son emplacement en mémoire, par exemple:

<__main__.Foo object at 0x7f80665abdd0>

Cette information n'est pas très utile, mais il n'y a aucun moyen de dériver comment on pourrait créer une représentation canonique d'une instance donnée, et c'est mieux que rien, au moins nous dire comment nous pourrions l'identifier de façon unique en mémoire.

Comment puis __repr__ sois utile?

Regardons comment cela peut être utile, en utilisant le shell Python et datetime objets. Nous devons d'abord importer le datetime module:

import datetime

Si nous appelons datetime.now dans le shell, nous verrons tout ce dont nous avons besoin pour recréer un objet datetime équivalent. Ceci est créé par le datetime __repr__:

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

Si nous imprimons un objet datetime, nous voyons un bon format lisible par l'homme (en fait, ISO). Ceci est implémenté par datetime __str__:

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

Il est simple de recréer l'objet que nous avons perdu parce que nous ne l'avons pas assigné à une variable en copiant et en collant __repr__ sortie, puis l'impression, et nous l'obtenons dans la même sortie lisible par l'homme que l'autre objet:

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

Comment puis-je les implémenter?

Au fur et à mesure que vous développez, vous voudrez être capable de reproduire des objets dans le même état, si possible. Ceci, par exemple, est la façon dont l'objet datetime définit __repr__ (Source Python). C'est assez complexe, à cause de tous les attributs nécessaires pour reproduire un tel objet:

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

Si vous voulez que votre objet ait une représentation plus lisible, vous pouvez implémenter __str__ prochain. Voici comment l'objet datetime (Source Python) met en oeuvre __str__, ce qu'il fait facilement parce qu'il a déjà une fonction pour l'afficher au format ISO:

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

Ensemble __repr__ = __str__?

Ceci est une critique d'une autre réponse ici qui suggère de réglage __repr__ = __str__.

Réglage __repr__ = __str__ est idiot - __repr__ est un repli pour __str__ et un __repr__, écrit pour l'usage des développeurs dans le débogage, devrait être écrit avant d'écrire un __str__.

Tu as besoin d'un __str__ uniquement lorsque vous avez besoin d'une représentation textuelle de l'objet.

Conclusion

Définir __repr__ Pour les objets que vous écrivez, vous et les autres développeurs avez un exemple reproductible lorsque vous l'utilisez lorsque vous développez. Définir __str__ lorsque vous avez besoin d'une représentation de chaîne lisible par un humain.


84
2018-01-25 02:01



En dehors de toutes les réponses données, je voudrais ajouter quelques points:

1) __repr__() est invoqué lorsque vous écrivez simplement le nom de l'objet sur la console python interactive et appuyez sur Entrée.

2) __str__() est invoqué lorsque vous utilisez un objet avec une instruction print.

3) Dans le cas, si __str__ est manquant, puis imprimer et toute fonction en utilisant str() invoque __repr__() d'objet.

4) __str__() des conteneurs, lorsqu'il est invoqué s'exécutera __repr__() méthode de ses éléments contenus.

5) str() appelé dans __str__() pourrait potentiellement recurse sans un cas de base, et une erreur sur la profondeur de récursivité maximale.

6) __repr__() pouvoir appeler repr() qui va tenter d'éviter automatiquement la récursion infinie, en remplaçant un objet déjà représenté par ....


12
2017-09-08 03:27



En toute honnêteté, eval(repr(obj)) n'est jamais utilisé. Si vous vous trouvez en train de l'utiliser, vous devriez arrêter, car eval est dangereux, et les chaînes sont un moyen très inefficace de sérialiser vos objets (utilisation pickle au lieu).

Par conséquent, je recommanderais de régler __repr__ = __str__. La raison en est que str(list) appels repr sur les éléments (je considère que c'est l'un des plus grands défauts de conception de Python qui n'a pas été traité par Python 3). Un réel repr ne sera probablement pas très utile que la sortie de print [your, objects].

Pour qualifier cela, dans mon expérience, le cas d'utilisation le plus utile de la repr La fonction est de mettre une chaîne à l'intérieur d'une autre chaîne (en utilisant la mise en forme de chaîne). De cette façon, vous n'avez pas à vous soucier d'échapper des citations ou quoi que ce soit. Mais notez qu'il n'y a pas eval passe ici.


11
2017-11-15 10:39



Pour le dire simplement:

__str__ est utilisé pour afficher une représentation sous forme de chaîne de votre objet être lu facilement par d'autres.

__repr__ est utilisé pour afficher une représentation sous forme de chaîne de la objet.

Disons que je veux créer un Fraction où la représentation sous forme de chaîne d'une fraction est '(1/2)' et l'objet (classe de fractions) doit être représentée par 'Fraction (1,2)'

Nous pouvons donc créer une classe Fraction simple:

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



A la page 358 du livre Script Python pour la science computationnelle Hans Petter Langtangen, il est clairement indiqué que

  • le __repr__vise à une représentation complète de la chaîne de l'objet;
  • le __str__ est de retourner une belle chaîne pour l'impression.

Donc, je préfère les comprendre comme

  • repr = reproduire
  • str = chaîne (représentation)

du point de vue de l'utilisateur bien que ce soit un malentendu que j'ai fait en apprenant python.

Un petit mais bon exemple est également donné sur la même page comme suit:

Exemple

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'

10
2018-05-21 16:34



De http://pyref.infogami.com/__str__ par effbot:

__str__ "calcule la représentation de chaîne" informelle "d'un objet. __repr__ en ce sens qu'il ne doit pas être une expression Python valide: une représentation plus pratique ou plus concise peut être utilisée à la place. "


9
2017-09-17 04:28