Différence entre __str__ et __repr__?

Réponses:

2727

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

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

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

L'implémentation 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__lequel agirait comme:

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

aurait été trop dangereux (par exemple, trop facile d'entrer dans une récursion infinie si les objets se référencent). Alors Python s'en sort. Notez qu'il y a une valeur par défaut qui est vraie: si __repr__est défini, et __str__ne l'est pas, l'objet se comportera comme si __str__=__repr__.

Cela signifie, en termes simples: presque chaque objet que vous implémentez devrait avoir une fonctionnalité __repr__utilisable pour comprendre l'objet. L'implémentation __str__est facultative: faites-le si vous avez besoin d'une fonctionnalité «jolie impression» (par exemple, utilisée par un générateur de rapports).

L'objectif __repr__est d'être sans ambiguïté

Permettez-moi de le dire tout de suite - 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. De plus, je crois que le gros défaut des débogueurs est leur nature fondamentale - la plupart des échecs que je débogue se sont produits il y a très longtemps, dans une galaxie très éloignée. Cela signifie que je crois, avec ferveur religieuse, à l'exploitation forestière. La journalisation est la pierre angulaire de tout système serveur décent de type feu et oubli. Python facilite la journalisation: avec peut-être des wrappers spécifiques à un 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 représentation utile, donc un code comme celui-ci peut simplement fonctionner. C'est pourquoi la chose «eval» apparaît: si vous avez suffisamment d'informations eval(repr(c))==c, cela signifie que vous savez tout ce qu'il y a à savoir c. Si c'est assez facile, au moins d'une manière floue, faites-le. Si ce n'est pas le cas, assurez-vous d'avoir suffisamment d'informations sur de ctoute façon. Je l'habitude d' utiliser un eval comme le format: "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 du constructeur - mais c'est une forme utile pour exprimer «c'est tout ce que vous devez savoir sur cette instance».

Remarque: je l'ai utilisé %rci-dessus, non %s. Vous voulez toujours utiliser repr()[ou un %rcaractère de mise en forme, de manière équivalente] à l'intérieur de l' __repr__implémentation, ou vous battez l'objectif de repr. Vous voulez pouvoir différencier MyClass(3)et MyClass("3").

L'objectif __str__est d'être lisible

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

Le conteneur __str__utilise des objets contenus '__repr__

Cela semble surprenant, non? C'est un peu, mais comment serait-il lisible s'il utilisait leur __str__?

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

Pas très. Plus précisément, les chaînes d'un conteneur trouveraient trop facile de perturber sa représentation. 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,

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

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

Sommaire

Implémentez __repr__pour n'importe quelle classe que vous implémentez. Cela devrait être une seconde nature. Implémentez-le __str__si vous pensez qu'il serait utile d'avoir une version chaîne qui pèche du côté de la lisibilité.

moshez
la source
154
Pas du tout d'accord avec votre opinion selon laquelle le débogage n'est pas la solution. Pour le développement, utilisez un débogueur (et / ou la journalisation), pour la production, utilisez la journalisation. Avec un débogueur, vous avez une vue de tout ce qui s'est mal passé lorsque le problème est survenu. Vous pouvez voir l'image complète. Sauf si vous vous connectez TOUT, vous ne pouvez pas obtenir cela. De plus, si vous enregistrez tout, vous devrez parcourir des tonnes de données pour obtenir ce que vous voulez.
Samuel
21
Excellente réponse (sauf le peu de non-utilisation de débogueurs). Je voudrais juste ajouter un lien vers cet autre Q&R sur str vs unicode en Python 3 qui pourrait être pertinent pour la discussion pour les personnes qui ont fait le changement.
ThatAintWorking
11
plus1 pour les débogueurs sont inutiles et ne valent pas un centime. Obtenez votre débit de journalisation à la place. Et oui, c'était un article bien écrit. Il s'est avéré __repr__que j'avais besoin de débogage. Merci de votre aide.
personal_cloud
7
votre folie de débogueur mise à part, j'ai appris le% r et ça vaut quand même le vote
Mickey Perlstein
7
sur le débogueur contre aucun débogueur: n'obtenez pas des opinions aussi ancrées. Dans certaines applications, le débogage n'est pas réaliste, généralement en temps réel ou lorsque votre code ne s'exécute qu'à distance sur une plateforme avec peu d'accès ou sans console. Dans la plupart des autres cas, il sera beaucoup plus rapide de s'arrêter à une exception pour enquêter ou de définir un point d'arrêt, car vous n'avez pas à parcourir des milliers de lignes de journalisation (ce qui encombrera votre disque et ralentira l'application). Enfin, il n'est pas toujours possible de se connecter, par exemple sur des appareils embarqués, le débogueur est aussi votre ami.
RedGlyph
523

Ma règle d'or: __repr__c'est pour les développeurs, __str__c'est pour les clients.

Ned Batchelder
la source
2
Cela est vrai car pour obj = uuid.uuid1 (), obj .__ str __ () est "2d7fc7f0-7706-11e9-94ae-0242ac110002" et obj .__ repr__ () est "UUID ('2d7fc7f0-7706-11e9-94ae-0242ac110002) ') ". Les développeurs ont besoin de (valeur + origine) alors que les clients ont besoin d'une valeur et ils se moquent de savoir comment ils l'ont obtenue!
Naren Yellavula
1
Ici, le client ne signifie pas nécessairement l'utilisateur final. C'est le client ou l'utilisateur de l'objet. Donc, si c'est un SDK, les développeurs du SDK utiliseront __str__donc les développeurs normaux ont un objet lisible. En revanche, __repr__c'est pour les développeurs du SDK eux-mêmes.
Shiplu Mokaddim
398

Sauf si vous agissez spécifiquement pour garantir 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 le 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 également utilisé pour __str__, mais pas vice versa.

Autres informations essentielles à savoir: __str__sur un conteneur intégré, utilise le __repr__, PAS le __str__, pour les éléments qu'il contient. Et, malgré les mots sur le sujet trouvés dans les documents typiques, presque personne ne prend la peine de faire __repr__des objets une chaîne qui evalpeut être utilisée pour construire un objet égal (c'est tout simplement trop difficile, ET ne pas savoir comment le module pertinent a été réellement importé le rend réellement à plat impossible).

Donc, mon conseil: concentrez-vous sur le fait de rendre __str__raisonnablement lisible par l'homme, et __repr__aussi sans ambiguïté que possible, même si cela interfère avec l'objectif flou et inaccessible de rendre __repr__la valeur retournée de 'acceptable comme entrée pour __eval__!

Alex Martelli
la source
34
Dans mes tests unitaires, je vérifie toujours que le résultat est eval(repr(foo))égal à un objet égal à foo. Vous avez raison, cela ne fonctionnera pas en dehors de mes cas de test car je ne sais pas comment le module est importé, mais cela garantit au moins qu'il fonctionne dans un contexte prévisible. Je pense que c'est une bonne façon d'évaluer si le résultat __repr__est suffisamment explicite. Faire cela dans un test unitaire permet également de s'assurer que les __repr__modifications apportées à la classe suivent.
Steven T. Snyder
4
J'essaie toujours de m'assurer que eval(repr(spam)) == spam(au moins dans le bon contexte), ou eval(repr(spam))soulève un SyntaxError. De cette façon, vous évitez la confusion. (Et c'est presque vrai pour les builtins et la plupart des stdlib, sauf, par exemple, des listes récursives, où a=[]; a.append(a); print(eval(repr(a)))vous donne [[Ellipses]]...) Bien sûr , je ne fais pas ça pour réellement utiliser eval(repr(spam)) , sauf un contrôle de santé mentale dans les tests unitaires ... mais je ne parfois copier et coller repr(spam)dans une session interactive.
abarnert
Pourquoi les conteneurs (listes, tuples) n'utiliseraient-ils pas __str__pour chaque élément au lieu de __repr__? Cela me semble tout à fait faux, car j'ai implémenté un __str__objet lisible dans mon objet et lorsqu'il fait partie d'une liste, je vois le plus laid à la __repr__place.
SuperGeo
Je viens de rencontrer un bug ennuyeux lié au fait qu'il eval(repr(x))échoue même pour les types intégrés: class A(str, Enum): X = 'x'déclenche SyntaxError eval(repr(A.X)). C'est triste, mais compréhensible. BTW, en eval(str(A.X))fait fonctionne, mais bien sûr seulement s'il class Aest dans la portée - donc ce n'est probablement pas très utile.
max
@SuperGeo D'autres réponses couvrent ceci: strélément d'utilisation du conteneur reprcar [1, 2, 3]! = ["1", "2, 3"].
mtraceur
163

__repr__: la représentation de l'objet python habituellement eval le reconvertira 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
Andrew Clark
la source
151

En bref, l'objectif de __repr__est d'être sans ambiguïté et __str__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. Il s'agit de la même valeur fournie par les conversions (guillemets inversés). Il est parfois utile de pouvoir accéder à cette opération comme une fonction ordinaire. Pour de nombreux types, cette fonction tente de renvoyer une chaîne qui donnerait un objet avec la même valeur lorsqu'elle est transmise à eval(), sinon la représentation est une chaîne entre crochets qui contient le nom du type de l'objet avec des informations supplémentaires comprenant souvent le nom et l'adresse de l'objet. Une classe peut contrôler ce que cette fonction renvoie pour ses instances en définissant une __repr__()méthode.

Voici la documentation de str:

str(object='')

Renvoie une chaîne contenant une représentation bien imprimable d'un objet. Pour les chaînes, cela renvoie la chaîne elle-même. La différence avec repr(object)est qu'il str(object)n'essaie pas toujours de renvoyer une chaîne acceptable pour eval(); son objectif est de renvoyer une chaîne imprimable. Si aucun argument est donné, renvoie la chaîne vide, ''.

bitoffdev
la source
1
Quelle est la signification de la chaîne imprimable ici? Pouvez-vous l'expliquer s'il vous plaît?
Vicrobot
115

Quelle est la différence entre __str__et __repr__en Python?

__str__(lu comme "dunder (double soulignement) chaîne") et __repr__(lu comme "dunder-repper" (pour "représentation")) sont deux méthodes spéciales qui renvoient des chaînes en fonction de l'état de l'objet.

__repr__fournit un comportement de sauvegarde s'il __str__est manquant.

Donc, il faut d'abord écrire un __repr__qui vous permet de réinstancier un objet équivalent à partir de la chaîne qu'il retourne, par exemple en utilisant evalou en le tapant caractère par caractère dans un shell Python.

À tout moment plus tard, on peut écrire un __str__pour une représentation en chaîne lisible par l'utilisateur de l'instance, quand on le juge nécessaire.

__str__

Si vous imprimez un objet, ou le transmettez à format,, str.formatou str, si une __str__méthode est définie, cette méthode sera appelée, sinon, __repr__elle sera utilisée.

__repr__

La __repr__méthode est appelée par la fonction intégrée repret correspond à ce qui est répercuté sur votre shell python lors de l'évaluation d'une expression qui renvoie un objet.

Puisqu'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.

Autrement dit, pour la plupart des objets, si vous tapez ce qui est imprimé par repr, vous devriez pouvoir 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 par défaut, vous imprimerez le module d'où 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>

Ces informations ne sont pas très utiles, mais il n'y a aucun moyen de déterminer comment créer avec précision une représentation canonique d'une instance donnée, et c'est mieux que rien, du moins en nous disant comment nous pourrions l'identifier de manière unique en mémoire.

Comment peut __repr__être utile?

Voyons à quel point cela peut être utile, en utilisant le shell et les datetimeobjets Python . Nous devons d'abord importer le datetimemodule:

import datetime

Si nous appelons datetime.nowdans 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 joli 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 affecté à une variable en copiant et en collant à partir de la __repr__sortie, puis en l'imprimant, 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 les implémenter?

Au fur et à mesure que vous développez, vous voudrez pouvoir reproduire des objets dans le même état, si possible. C'est par exemple ainsi que définit l'objet datetime __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 = "%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

Si vous souhaitez que votre objet ait une représentation plus lisible par l'homme, vous pouvez l'implémenter __str__ensuite. Voici comment l'objet datetime ( source Python ) implémente __str__, ce qu'il fait facilement car il a déjà une fonction pour l'afficher au format ISO:

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

Set __repr__ = __str__?

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

Le réglage __repr__ = __str__est stupide - __repr__est un substitut pour __str__et un __repr__, écrit pour les développeurs à des fins de débogage, doit être écrit avant d'écrire un __str__.

Vous __str__n'en avez besoin que lorsque vous avez besoin d'une représentation textuelle de l'objet.

Conclusion

Définissez __repr__pour les objets que vous écrivez afin que vous et les autres développeurs ayez un exemple reproductible lorsque vous l'utilisez pendant votre développement. Définissez __str__quand vous avez besoin d'une représentation en chaîne lisible par l'homme.

Aaron Hall
la source
Cela ne devrait-il pas être quelque chose du genre type(obj).__qualname__?
Solomon Ucko
@SolomonUcko oui en Python 3, cela semble être le cas - j'ai cherché le code source où cela est implémenté et je mettrai à jour ma réponse avec ces informations lorsque je les rassemblerai.
Aaron Hall
33

À la page 358 du livre Python scripting for computational science de Hans Petter Langtangen, il indique clairement que

  • Le __repr__vise à une représentation complète de la chaîne de l'objet;
  • Il __str__s'agit de renvoyer une jolie 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 lors de l'apprentissage du 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'
Yong Yang
la source
C'est à la p. # 351.
jiten
4
C'est un peu trompeur de parler de reprreproduire. Il vaut mieux y penser comme représentant.
NelsonGon
31

Outre 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 l'instruction print.

3) Au cas où, s'il __str__manque, imprimer et toute fonction utilisant des str()invocations __repr__()d'objet.

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

5) str()appelé à l'intérieur __str__()pourrait potentiellement récurrence sans cas de base, et erreur sur la profondeur de récursivité maximale.

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

Mangu Singh Rajpurohit
la source
14

Pour le dire simplement:

__str__est utilisé pour afficher une représentation sous forme de chaîne de votre objet pour être lu facilement par les autres.

__repr__est utilisé pour afficher une représentation sous forme de chaîne de l' objet.

Disons que je veux créer une Fractionclasse où la représentation sous forme de chaîne d'une fraction est '(1/2)' et l'objet (classe Fraction) doit être représenté comme '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)
Zer0
la source
13

En toute honnêteté, eval(repr(obj))n'est jamais utilisé. Si vous vous retrouvez à l'utiliser, vous devez vous arrêter, car evalc'est dangereux, et les chaînes sont un moyen très inefficace de sérialiser vos objets (utilisez pickleplutôt).

Par conséquent, je recommanderais le réglage __repr__ = __str__. La raison en est que cela fait str(list)appel repraux éléments (je considère que c'est l'un des plus gros défauts de conception de Python qui n'a pas été corrigé par Python 3). Un réel reprne sera probablement pas très utile comme sortie de print [your, objects].

Pour qualifier cela, d'après mon expérience, le cas d'utilisation le plus utile de la reprfonction est de mettre une chaîne à l'intérieur d'une autre chaîne (en utilisant le formatage de chaîne). De cette façon, vous n'avez pas à vous soucier d'échapper aux citations ou à quoi que ce soit. Mais notez qu'il ne se evalpasse rien ici.

asmeurer
la source
19
Je pense que cela manque le point. L'utilisation de eval(repr(obj))est un test d'intégrité et une règle de base - si cela recrée correctement l'objet d'origine, alors vous avez une __repr__implémentation décente . Il n'est pas prévu que vous sérialisiez des objets de cette façon.
jwg
7
evaln'est pas intrinsèquement dangereux. Est -ce pas plus dangereux que unlink, openou l' écriture de fichiers. Devrions-nous arrêter d'écrire dans des fichiers parce qu'une attaque malveillante pourrait peut-être utiliser un chemin de fichier arbitraire pour mettre du contenu à l'intérieur? Tout est dangereux s'il est bêtement utilisé par des gens stupides. L'idiotie est dangereuse. Les effets de Dunning-Kruger sont dangereux. evalest juste une fonction.
Luis Masuelli
12

À partir d' un Wiki de référence Python (non officiel) (copie d'archive) par effbot:

__str__" calcule la représentation sous forme de chaîne" informelle "d'un objet. Cela diffère du __repr__fait qu'il ne doit pas nécessairement être une expression Python valide: une représentation plus pratique ou concise peut être utilisée à la place. "

Casebash
la source
3
__repr__n'est en aucun cas requis pour renvoyer une expression Python vaild.
Mad Physicist
10

str - Crée un nouvel objet chaîne à partir de l'objet donné.

repr - Renvoie la représentation sous forme de chaîne canonique de l'objet.

Les différences:

str ():

  • rend l'objet lisible
  • génère une sortie pour l'utilisateur final

repr ():

  • a besoin de code qui reproduit l'objet
  • génère une sortie pour le développeur
Inconnu
la source
8

Un aspect qui manque dans d'autres réponses. Il est vrai qu'en général le schéma est:

  • Objectif __str__: lisible par l'homme
  • Objectif __repr__: sans ambiguïté, peut-être lisible par machine viaeval

Malheureusement, cette différenciation est imparfaite, car Python REPL et IPython utilisent également __repr__pour imprimer des objets dans une console REPL (voir les questions connexes pour Python et IPython ). Ainsi, les projets ciblés pour le travail sur console interactive (par exemple, Numpy ou Pandas) ont commencé à ignorer les règles ci-dessus et à fournir une __repr__implémentation lisible par l'homme .

bluenote10
la source
7

Extrait du livre Fluent Python :

Une exigence de base pour un objet Python est de fournir des représentations de chaîne utilisables de lui-même, une utilisée pour le débogage et la journalisation, une autre pour la présentation aux utilisateurs finaux. C'est pourquoi les
méthodes spéciales __repr__et __str__existent dans le modèle de données.

Ijaz Ahmad Khan
la source
5

D'excellentes réponses couvrent déjà la différence entre __str__et __repr__, ce qui pour moi se résume à ce que le premier soit lisible même par un utilisateur final, et que le second soit aussi utile que possible aux développeurs. Compte tenu de cela, je trouve que l'implémentation par défaut de __repr__souvent échoue à atteindre cet objectif car elle omet les informations utiles aux développeurs.

Pour cette raison, si j'en ai un assez simple __str__, j'essaye généralement de tirer le meilleur parti des deux mondes avec quelque chose comme:

def __repr__(self):
    return '{0} ({1})'.format(object.__repr__(self), str(self))
orome
la source
4

Une chose importante à garder à l'esprit est que le conteneur __str__utilise des objets contenus __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 privilégie la non-ambiguïté sur la lisibilité , l' __str__appel d'un tupleappelle les objets contenus __repr__, la représentation "formelle" d'un objet. Bien que la représentation formelle soit plus difficile à lire qu'une représentation informelle, elle est sans ambiguïté et plus robuste contre les bogues.

zangw
la source
Il utilise __repr__ quand il ( __str__) n'est pas défini! Vous vous trompez donc.
jiten
4

En un mot:

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
la source
4
>>> print(decimal.Decimal(23) / decimal.Decimal("1.05"))
21.90476190476190476190476190
>>> decimal.Decimal(23) / decimal.Decimal("1.05")
Decimal('21.90476190476190476190476190')

Quand print()est appelé, le résultat du decimal.Decimal(23) / decimal.Decimal("1.05")nombre brut est imprimé; cette sortie est sous forme de chaîne qui peut être réalisée avec __str__(). Si nous entrons simplement l'expression, nous obtenons une decimal.Decimalsortie - cette sortie est sous une forme représentative qui peut être obtenue avec __repr__(). Tous les objets Python ont deux formes de sortie. La forme de chaîne est conçue pour être lisible par l'homme. La forme représentationnelle est conçue pour produire une sortie qui, si elle était envoyée à un interpréteur Python, reproduirait (si possible) l'objet représenté.

BattleDrum
la source
4

__str__peut être invoqué sur un objet en appelant str(obj)et doit renvoyer une chaîne lisible par l'homme.

__repr__peut être invoqué sur un objet en appelant repr(obj)et doit renvoyer un objet interne (champs / attributs d'objet)

Cet exemple peut aider:

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
la source
3

Les comprendre __str__et __repr__les distinguer de manière intuitive et permanente.

__str__renvoyer la chaîne déguisée corps d'un objet donné pour une lecture des yeux
__repr__retourner le corps de chair réel d'un objet donné (retour lui-même) pour une ambiguïté à identifier.

Voir dans un exemple

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

Quant à __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.

Nous pouvons __repr__facilement effectuer des opérations arithmétiques sur les résultats.

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)

si appliquer l'opération sur __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'

Ne renvoie rien d'autre qu'une erreur.

Un autre exemple.

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

J'espère que cela vous aidera à construire des terrains concrets pour explorer plus de réponses.

Calcul
la source
3
  1. __str__doit renvoyer un objet chaîne alors qu'il __repr__peut renvoyer n'importe quelle expression python.
  2. Si l' __str__implémentation est manquante, la __repr__fonction est utilisée comme solution de repli. Il n'y a pas de solution de repli si __repr__l'implémentation de fonction est manquante.
  3. Si la __repr__fonction renvoie une représentation String de l'objet, nous pouvons ignorer l'implémentation de la __str__fonction.

Source: https://www.journaldev.com/22460/python-str-repr-functions

Sampath
la source
2

__repr__est utilisé partout, sauf par les méthodes printet str(quand a __str__est défini!)

techkuz
la source