Quelle est la différence entre __str__
et __repr__
en Python?
la source
Quelle est la différence entre __str__
et __repr__
en Python?
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 :
__repr__
l'objectif est d'être sans ambiguïté__str__
le but est d'être lisible__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 c
toute 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é %r
ci-dessus, non %s
. Vous voulez toujours utiliser repr()
[ou un %r
caractè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é.
__repr__
que j'avais besoin de débogage. Merci de votre aide.Ma règle d'or:
__repr__
c'est pour les développeurs,__str__
c'est pour les clients.la source
__str__
donc les développeurs normaux ont un objet lisible. En revanche,__repr__
c'est pour les développeurs du SDK eux-mêmes.Sauf si vous agissez spécifiquement pour garantir le contraire, la plupart des classes n'ont pas de résultats utiles pour:
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 ...: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 quieval
peut ê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__
!la source
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.eval(repr(spam)) == spam
(au moins dans le bon contexte), oueval(repr(spam))
soulève unSyntaxError
. 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 utilisereval(repr(spam))
, sauf un contrôle de santé mentale dans les tests unitaires ... mais je ne parfois copier et collerrepr(spam)
dans une session interactive.__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.eval(repr(x))
échoue même pour les types intégrés:class A(str, Enum): X = 'x'
déclenche SyntaxErroreval(repr(A.X))
. C'est triste, mais compréhensible. BTW, eneval(str(A.X))
fait fonctionne, mais bien sûr seulement s'ilclass A
est dans la portée - donc ce n'est probablement pas très utile.str
élément d'utilisation du conteneurrepr
car[1, 2, 3]
! =["1", "2, 3"]
.__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 textepar exemple
la source
Voici un bon exemple:
Lisez cette documentation pour repr:
Voici la documentation de str:
la source
__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 utilisanteval
ou 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.format
oustr
, 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éerepr
et 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
: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: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:
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
datetime
objets Python . Nous devons d'abord importer ledatetime
module: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__
: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__
: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: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: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: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.la source
type(obj).__qualname__
?À la page 358 du livre Python scripting for computational science de Hans Petter Langtangen, il indique clairement que
__repr__
vise à une représentation complète de la chaîne de l'objet;__str__
s'agit de renvoyer une jolie chaîne pour l'impression.Donc, je préfère les comprendre comme
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
la source
repr
reproduire. Il vaut mieux y penser comme représentant.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 desstr()
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 appelerrepr()
ce qui tentera d'éviter automatiquement la récursion infinie, en remplaçant un objet déjà représenté par...
.la source
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
Fraction
classe 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:
la source
En toute honnêteté,
eval(repr(obj))
n'est jamais utilisé. Si vous vous retrouvez à l'utiliser, vous devez vous arrêter, careval
c'est dangereux, et les chaînes sont un moyen très inefficace de sérialiser vos objets (utilisezpickle
plutôt).Par conséquent, je recommanderais le réglage
__repr__ = __str__
. La raison en est que cela faitstr(list)
appelrepr
aux é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éelrepr
ne sera probablement pas très utile comme sortie deprint [your, objects]
.Pour qualifier cela, d'après mon expérience, le cas d'utilisation le plus utile de la
repr
fonction 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 seeval
passe rien ici.la source
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.eval
n'est pas intrinsèquement dangereux. Est -ce pas plus dangereux queunlink
,open
ou 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.eval
est juste une fonction.À 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. "la source
__repr__
n'est en aucun cas requis pour renvoyer une expression Python vaild.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 ():
repr ():
la source
Un aspect qui manque dans d'autres réponses. Il est vrai qu'en général le schéma est:
__str__
: lisible par l'homme__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 .la source
Extrait du livre Fluent Python :
la source
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:la source
Python privilégie la non-ambiguïté sur la lisibilité , l'
__str__
appel d'untuple
appelle 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.la source
__repr__
quand il (__str__
) n'est pas défini! Vous vous trompez donc.En un mot:
la source
Quand
print()
est appelé, le résultat dudecimal.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 unedecimal.Decimal
sortie - 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é.la source
__str__
peut être invoqué sur un objet en appelantstr(obj)
et doit renvoyer une chaîne lisible par l'homme.__repr__
peut être invoqué sur un objet en appelantrepr(obj)
et doit renvoyer un objet interne (champs / attributs d'objet)Cet exemple peut aider:
la source
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
Quant à
__repr__
Nous pouvons
__repr__
facilement effectuer des opérations arithmétiques sur les résultats.si appliquer l'opération sur
__str__
Ne renvoie rien d'autre qu'une erreur.
Un autre exemple.
J'espère que cela vous aidera à construire des terrains concrets pour explorer plus de réponses.
la source
__str__
doit renvoyer un objet chaîne alors qu'il__repr__
peut renvoyer n'importe quelle expression python.__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.__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
la source
__repr__
est utilisé partout, sauf par les méthodesprint
etstr
(quand a__str__
est défini!)la source