Quelle est la différence entre __str__
et __repr__
en Python?
Alex résume bien mais, étonnamment, était trop succinct.
Tout d’abord, permettez-moi de répéter les points principaux de post d’Alex :
__repr__
but est d'être sans ambiguïté__str__
objectif doit être lisible__str__
du conteneur utilise les __repr__
des objets contenusL'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, ayant un défaut pour __repr__
qui agirait comme:
return "%s(%r)" % (self.__class__, self.__dict__)
aurait été trop dangereux (par exemple, il est trop facile d'entrer dans une récursion infinie si les objets se référent). Donc, Python s'est échappé. Notez qu'il existe une valeur par défaut qui est true: si __repr__
est défini et si __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 doit avoir un __repr__
fonctionnel, utilisable pour comprendre l’objet. L'implémentation de __str__
est facultative: faites-le si vous avez besoin d'une fonctionnalité de "jolie impression" (utilisée par exemple par un générateur de rapport).
L'objectif de __repr__
est d'être sans ambiguïté
Laissez-moi sortir et le 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. De plus, je pense 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 une ferveur religieuse, à l'exploitation forestière. La journalisation est la pierre angulaire de tout système serveur décent "fire-and-oublie". Python facilite la journalisation: avec peut-être des wrappers spécifiques à un projet, tout ce dont vous avez besoin est une
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 un repr utile, afin que le code comme ça puisse fonctionner. C’est la raison pour laquelle "eval" s’affiche: si vous avez assez d’informations pour que eval(repr(c))==c
, cela signifie que vous savez tout ce que vous devez savoir sur c
. Si cela est assez facile, au moins de manière floue, faites-le. Sinon, assurez-vous de disposer de suffisamment d'informations sur c
. J'utilise habituellement un format semblable à eval: "MyClass(this=%r,that=%r)" % (self.this,self.that)
. Cela ne signifie pas que vous pouvez réellement construire MyClass, ni que ce sont les bons arguments de constructeur, mais c'est une forme utile pour exprimer "c'est tout ce que vous devez savoir sur cette instance".
Remarque: J'ai utilisé %r
ci-dessus, pas %s
. Vous voulez toujours utiliser repr()
[ou %r
, de manière équivalente] dans l’implémentation de __repr__
, sinon vous éliminez l’objectif de repr. Vous voulez pouvoir 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, il suffit de donner à str la forme 192.168.1.1. Lors de l'implémentation d'une abstraction de date/heure, str peut être "2010/4/12 15:35:22", etc. Le but est de la représenter de manière à ce qu'un utilisateur, et non un programmeur, veuille la lire. Coupez les chiffres inutiles, faites semblant d'être une autre classe - tant que la lisibilité sera prise en charge, c'est une amélioration.
Le __str__
du conteneur utilise le __repr__
des objets contenus
Cela semble surprenant, n'est-ce pas? C'est un peu, mais comment lisible serait
[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 auraient beaucoup trop de mal à perturber sa représentation. Face à l'ambiguïté, rappelez-vous que 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 avec les dictionnaires.
Résumé
Implémentez __repr__
pour toute classe que vous implémentez. Cela devrait être une seconde nature. Implémentez __str__
si vous pensez qu'il serait utile de disposer d'une version de chaîne erronée du côté de la lisibilité.
Ma règle générale: __repr__
est destiné aux développeurs, __str__
est destiné aux clients.
Sauf si vous agissez spécifiquement pour vous assurer du contraire, la plupart des classes n'offrent 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, ni aucune information au-delà de la classe et de la variable id
de l'objet. 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 l'inverse.
Autres informations essentielles à connaître: __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 la documentation typique, presque personne ne dérange que le __repr__
des objets soit une chaîne que eval
peut utiliser pour construire un objet égal (c'est trop difficile, ET je ne sais pas la manière dont le module concerné a été réellement importé le rend totalement impossible).
Donc, mon conseil: cherchez à rendre __str__
lisible par tout un chacun, et __repr__
aussi sans ambiguïté que possible, même si cela interfère avec l'objectif inatteignable de rendre acceptable la valeur de __repr__
. en entrée de __eval__
!
En bref, le but de
__repr__
est d'être sans ambiguïté et__str__
doit ê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 générée par les conversions (devis inversés). Il est parfois utile de pouvoir accéder à cette opération en tant que fonction ordinaire. Pour de nombreux types, cette fonction tente de renvoyer une chaîne qui donnerait un objet avec la même valeur si elle est transmise à
eval()
. Sinon, la représentation est une chaîne entourée de crochets angulaires contenant le nom du type de l'objet avec des informations comprenant souvent le nom et l'adresse de l'objet. Une classe peut contrôler ce que cette fonction retourne pour ses instances en définissant une méthode__repr__()
.
Voici la documentation pour str:
str(object='')
Renvoie une chaîne contenant une représentation joliment imprimable d'un objet. Pour les chaînes, cela retourne la chaîne elle-même. La différence avec
repr(object)
est questr(object)
ne tente pas toujours de renvoyer une chaîne acceptable poureval()
; son but est de retourner une chaîne imprimable. Si aucun argument n'est fourni, retourne la chaîne vide,''
.
Quelle est la différence entre
__str__
et__repr__
en Python?
__str__
(lu comme "chaîne dunder (double soulignement)") et __repr__
(lu comme "dunder-repper" (pour "representation")) 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__
qui vous permet de restituer un objet équivalent à partir de la chaîne qu’il renvoie, par exemple. en utilisant eval
ou en le saisissant caractère par caractère dans un shell Python.
À tout moment, on peut écrire un __str__
pour une représentation sous forme de 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
ou str
, alors si une méthode __str__
est définie, cette méthode sera appelée, sinon, __repr__
sera utilisé.
__repr__
La méthode __repr__
est appelée par la fonction intégrée repr
et correspond à l'écho sur votre shell python lorsqu'il évalue une expression renvoyant 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 saisissez 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.
__repr__
L'objet par défaut __repr__
est ( C Python source ) 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>
Cette information n’est pas très utile, mais il n’ya aucun moyen de déterminer comment on pourrait créer avec précision une représentation canonique d’un événement donné, et c’est mieux que rien, du moins nous dire comment nous pourrions l’identifier de manière unique en mémoire.
__repr__
peut-il être utile?Voyons à quel point cela peut être utile, en utilisant les objets Python Shell et datetime
. Nous devons d’abord importer le module datetime
:
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 date/heure __repr__
:
>>> datetime.datetime.now()
datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
Si nous imprimons un objet date/heure, nous voyons un format lisible par Nice (en fait, ISO). Ceci est implémenté par __str__
:
>>> print(datetime.datetime.now())
2015-01-24 20:05:44.977951
Il est simple de recréer l’objet perdu car nous ne l’avons pas affectée à une variable en copiant-collant à partir de la sortie __repr__
, puis en l’imprimant, et nous l’avons dans le même résultat lisible par l’homme l'autre objet:
>>> the_past = datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
>>> print(the_past)
2015-01-24 20:05:36.491180
Au fur et à mesure que vous développez, vous souhaiterez pouvoir reproduire des objets dans le même état, si possible. C’est le cas, par exemple, de 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 = "%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 voulez que votre objet ait une représentation plus lisible par l'homme, vous pouvez implémenter __str__
next. Voici comment l'objet datetime ( source Python ) implémente __str__
, ce qu'il fait facilement car il dispose déjà d'une fonction pour l'afficher au format ISO:
def __str__(self):
"Convert to string, for str()."
return self.isoformat(sep=' ')
__repr__ = __str__
?Ceci est une critique d'une autre réponse ici qui suggère de définir __repr__ = __str__
.
La définition de __repr__ = __str__
est idiote - __repr__
est un repli pour __str__
et un __repr__
, écrit à l'usage des développeurs pour le débogage, doit être écrit avant d'écrire un __str__
.
Vous n'avez besoin d'un __str__
que lorsque vous avez besoin d'une représentation textuelle de l'objet.
Définissez __repr__
pour les objets que vous écrivez afin que vous et les autres développeurs disposiez d'un exemple reproductible lorsque vous l'utilisez au cours de votre développement. Définissez __str__
lorsque vous avez besoin d’une représentation sous forme de chaîne lisible par l’homme.
Outre toutes les réponses données, je voudrais ajouter quelques points: -
1) __repr__()
est appelé lorsque vous écrivez simplement le nom de l'objet sur la console interactive python et appuyez sur Entrée.
2) __str__()
est appelé lorsque vous utilisez un objet avec une instruction print.
3) Dans le cas où __str__
est manquant, alors l'impression et toute fonction utilisant str()
invoquera __repr__()
de l'objet.
4) __str__()
des conteneurs, une fois appelé, exécutera la méthode __repr__()
de ses éléments contenus.
5) str()
appelée dans __str__()
pourrait potentiellement être récursive sans cas de base et erreur sur la profondeur de récursivité maximale.
6) __repr__()
peut appeler repr()
qui tentera d'éviter automatiquement la récursion infinie en remplaçant un objet déjà représenté par ...
.
Sur la page 358 du livre Scripting Python pour la science informatique de Hans Petter Langtangen, il est clairement indiqué que
__repr__
vise une représentation sous forme de chaîne complète de l'objet;__str__
doit renvoyer une chaîne de Nice 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 de python.
Un petit mais bon exemple est également donné sur la même page comme suit:
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'
En toute honnêteté, eval(repr(obj))
n'est jamais utilisé. Si vous l'utilisez, arrêtez-vous, car eval
est dangereux et les chaînes sont un moyen très inefficace de sérialiser vos objets (utilisez plutôt pickle
).
Par conséquent, je recommanderais de régler __repr__ = __str__
. La raison en est que str(list)
appelle repr
sur les éléments (j'estime qu'il s'agit de l'un des plus gros défauts de conception de Python qui n'a pas été résolu par Python 3) Un repr
réel ne sera probablement pas très utile en tant que résultat de print [your, objects]
.
D'après mon expérience, le cas d'utilisation le plus utile de la fonction repr
consiste à insérer une chaîne dans une autre chaîne (à l'aide du formatage 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 de eval
qui se passe ici.
Pour le dire simplement:
__str__
est utilisé pour afficher une représentation sous forme de chaîne de votre objet à lire facilement par d'autres.
__repr__
est utilisé pour afficher une représentation sous forme de chaîne de l'objet the.
Supposons que je souhaite créer une classe Fraction
dans laquelle la représentation sous forme de chaîne d'une fraction est '(1/2)' et l'objet (classe de fraction) doit être représenté par 'Fraction (1,2)'
Nous pouvons donc créer une classe de fractions 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)
De n (Un non officiel) Python Wiki de référence (copie d'archive) par effbot:
__str__
" calcule la représentation sous forme de chaîne" informelle "d'un objet. Elle diffère de __repr__
en ce qu'elle ne doit pas nécessairement être valide Python expression: une représentation plus pratique ou plus concise peut être utilisée à la place. "
Un aspect qui manque dans d'autres réponses. Il est vrai qu'en général, le schéma est le suivant:
__str__
: lisible par l'homme__repr__
: sans ambiguïté, éventuellement lisible par machine via eval
Malheureusement, cette différenciation est erronée, car Python REPL ainsi que IPython utilisent __repr__
pour imprimer des objets dans une console REPL (voir les questions connexes à ce sujet). Python et IPython ). Ainsi, les projets destinés au travail en console interactive (par exemple, Numpy ou Pandas) ont commencé à ignorer les règles ci-dessus et à fournir une implémentation __repr__
lisible par l'homme.
str
- Crée un nouvel objet chaîne à partir de l'objet donné.
repr
- Retourne la représentation canonique de l'objet.
Les différences:
str ():
repr ():
Tellement plus clair de blog
str est comme toString. créé afin que vous puissiez imprimer les données repr est comme sérialiser, ou pickle. Comment je recrée-t-il cet objet si j'ai besoin de le faire en utilisant eval ()
>>> import datetime
>>> now = datetime.datetime.now()
>>> str(now)
'2015-04-04 20:51:31.766862'
>>> repr(now)
'datetime.datetime(2015, 4, 4, 20, 51, 31, 766862)'
>>mydate = eval(repr(now))
Extrait du livre Fluent Python:
Une exigence de base pour un objet Python est de fournir ses propres représentations sous forme de chaîne, l'une utilisée pour le débogage et la journalisation, l'autre pour la présentation aux utilisateurs finaux. C'est pourquoi le
Des méthodes spéciales__repr__
et__str__
existent dans le modèle de données.
D'excellentes réponses couvrent déjà la différence entre __str__
et __repr__
, ce qui pour moi revient à dire que la première est lisible, même par un utilisateur final, et que ce dernier est aussi utile que possible aux développeurs. Cela dit, j’estime que l’implémentation par défaut de __repr__
échoue souvent à atteindre cet objectif car elle omet des informations utiles aux développeurs.
Pour cette raison, si j’ai un assez simple __str__
, j’essaie généralement d’obtenir le meilleur des deux mondes avec quelque chose comme:
def __repr__(self):
return '{0} ({1})'.format(object.__repr__(self), str(self))
>>> print(decimal.Decimal(23) / decimal.Decimal("1.05"))
21.90476190476190476190476190
>>> decimal.Decimal(23) / decimal.Decimal("1.05")
Decimal('21.90476190476190476190476190')
Lorsque print()
est appelé sur le résultat de decimal.Decimal(23) / decimal.Decimal("1.05")
, le numéro brut est imprimé. cette sortie est en sous forme de chaîne qui peut être obtenue avec __str__()
. Si nous saisissons simplement l'expression, nous obtenons une sortie decimal.Decimal
- cette sortie est sous la forme forme de représentation 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 de représentation est conçue pour produire une sortie qui, si elle était transmise à un interprète Python, reproduirait (dans la mesure du possible) l'objet représenté.
Une chose importante à garder à l'esprit est que le
__str__
du conteneur utilise les 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 lisibilité sans ambiguïté, l'appel __str__
d'un Tuple
appelle les objets contenus '__repr__
, le "formel" représentation 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 bugs.
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'
Comprenez __str__
et __repr__
de manière intuitive et distincte.
__str__
retourne le corps déguisé en chaîne d'un objet donné pour qu'il soit lisible par les yeux__repr__
renvoie le corps de chair réel d'un objet donné (se retourne lui-même) afin qu'il soit identifié sans ambiguïté.
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 effectuer des opérations arithmétiques sur les résultats de __repr__
facilement.
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'
Retourne rien mais 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 bases concrètes pour explorer plus de réponses.
__repr__
est utilisé partout, sauf par les méthodes print
et str
(lorsqu'un __str__
est défini!)
__str__
doit renvoyer un objet chaîne alors que __repr__
peut renvoyer n'importe quelle expression python.__str__
est manquante, la fonction __repr__
est utilisée comme solution de secours. Il n'y a pas de solution de rechange si l'implémentation de la fonction __repr__
est manquante.__repr__
renvoie une représentation sous forme de chaîne de l'objet, nous pouvons ignorer l'implémentation de la fonction __str__
.Source: https://www.journaldev.com/22460/python-str-repr-functions
__str__
peut être appelé sur un objet en appelant str(obj)
et devrait renvoyer une chaîne lisible par l'homme.
__repr__
peut être appelé 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