Différence entre str Et repr?
Quelle est la différence entre __str__
et __repr__
dans Python
?
21 réponses
Alex résumé mais, étonnamment, était trop succinct.
tout d'abord, permettez-moi de réitérer les principaux points dans Alex's post :
- L'implémentation par défaut est inutile (il est difficile de penser à celle qui ne le serait pas, mais ouais)
-
__repr__
l'objectif est d'être sans ambiguïté -
__str__
l'objectif est d'être lisible - 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. Toutefois, 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, trop facile d'entrer dans une récursion infinie si les objets se réfèrent les uns aux autres). Donc Python est viré. Notez qu'il y a un défaut qui est true: 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 mettez en œuvre devrait avoir un __repr__
fonctionnel qui est utilisable pour comprendre l'objet. La mise en œuvre de __str__
est facultative: faites-le si vous avez besoin d'une fonctionnalité" pretty print " (par exemple, utilisé par un rapport générateur.)
le but 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é un sérieusement. En outre, je crois que la grande faille dans les débogueurs est leur nature fondamentale - la plupart des échecs que je corrige se sont produits il y a longtemps, dans une galaxie très lointaine. Cela signifie que je crois, avec des religieux ferveur, dans l'exploitation forestière. La journalisation est l'élément vital de tout système de serveur fire-and-forget décent. Python rend facile de se connecter: avec peut-être quelques enveloppements 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 mettez en œuvre a un repr utile, de sorte que le code comme cela peut juste fonctionner. C'est pourquoi la chose "eval" apparaît: si vous avez assez d'informations pour eval(repr(c))==c
, cela signifie que vous savez tout ce qu'il y a à savoir sur c
. Si c'est assez facile, au moins dans un flou manière, le faire. Si non, assurez-vous que vous avez assez d'informations sur c
de toute façon. J'utilise habituellement un format eval-like: "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 à propos de cette instance".
Note: j'ai utilisé %r
ci-dessus, pas %s
. Vous avez toujours vous voulez utiliser le caractère de formatage repr()
[ou %r
, de façon équivalente] à l'intérieur de la mise en œuvre __repr__
, ou vous allez à l'encontre de l'objectif de repr. Vous voulez pouvoir différencier MyClass(3)
et MyClass("3")
.
le but de __str__
doit être lisible
en particulier, il n'est pas destiné à être sans ambiguïté - avis que str(3)==str("3")
. De même, si vous mettez en œuvre une abstraction IP, ayant le str de ressembler à 192.168.1.1 est tout simplement parfait. Lors de la mise en œuvre d'un abstraction date/heure, la DOD peut être "2010/4/12 15:35:22", etc. Le but est de représenter de façon qu'un utilisateur, pas un programmeur, voudrais le lire. Couper des chiffres inutiles, prétendre être une autre classe - tant qu'elle soutient la lisibilité, c'est une amélioration.
Conteneur __str__
utilise des objets contenus’ __repr__
cela semble surprenant, n'est-ce pas? Il 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]
be? Pas très. Plus précisément, les chaînes dans un conteneur trouveraient beaucoup trop facile de perturber sa représentation de chaîne. Face à l'ambiguïté, rappelez-vous, Python résiste à la tentation de le deviner. Si vous voulez le comportement ci-dessus lorsque vous imprimez une liste, juste
print "[" + ", ".join(l) + "]"
(vous pouvez probablement aussi trouver quoi faire à propos des dictionnaires.
résumé
mettre en Œuvre __repr__
pour toute la classe à mettre en œuvre. Cela devrait être une seconde nature. Implémenter __str__
si vous pensez qu'il serait utile d'avoir une version string qui se trompe du côté de plus de lisibilité en faveur de plus d'ambiguïté.
Ma règle d'or: __repr__
est pour les développeurs", 151910920" est pour les clients.
sauf si vous agissez spécifiquement pour assurer autrement, la plupart des classes n'ont pas de résultats utiles pour l'un ou l'autre:
>>> 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 remplacez uniquement 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 outrepassez __repr__
, c'est aussi utilisé pour __str__
, mais pas vice versa.
autres informations cruciales à savoir: __str__
sur intégré le sur le conteneur utilise le __repr__
, PAS le __str__
, pour les éléments qu'il contient. Et, en dépit des mots sur le sujet trouvés dans les docs typiques, peu de gens dérange faire le __repr__
des objets être une chaîne que eval
peut utiliser pour construire un objet égal (c'est juste trop dur, et ne pas savoir comment le module concerné a été effectivement importé rend en fait flat out impossible).
donc, mon conseil: se concentrer sur la fabrication __str__
raisonnablement lisible par l'homme, et __repr__
aussi sans ambiguïté que vous le pouvez, même si cela interfère avec l'objectif fuzzy inaccessible de faire __repr__
valeur retournée acceptable comme entrée à __eval__
!
__repr__
: la représentation de l'objet python habituellement eval le convertira de nouveau en cet objet
__str__
: est-ce que ce que vous pensez est cet objet sous forme de texte
p.ex.
>>> 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
En bref, l'objectif de la
__repr__
est d'être sans équivoque et__str__
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)'
lire 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 obtenue par conversions (inverse). citation.) Il est parfois utile de pouvoir accéder à cette opération une fonction ordinaire. Pour de nombreux types, cette fonction fait une tentative pour retourner une chaîne qui donnerait un objet avec la même valeur lorsque le passé à
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 souvent, y compris le nom et adresse de l'objet. Une classe peut contrôler ce que cette fonction retourner pour ses instances en définissant une méthode__repr__()
.
Voici la documentation pour str:
str(object='')
retourner une corde contenant un joli imprimable représentation d'un objet. Pour les cordes, ceci renvoie la corde m'. La différence avec
repr(object)
est questr(object)
ne fait pas toujours essayer de retourner une chaîne qui est acceptable poureval()
; son le but est de retourner une chaîne imprimable. Si aucun argument n'est donné, renvoie la chaîne vide,''
.
Quelle est la différence entre
__str__
et__repr__
en Python?
__str__
("dunder (double-underscore) string") et __repr__
("dunder-repper" pour "representation") sont deux méthodes spéciales qui renvoient des chaînes basées sur l'état de l'objet.
__repr__
fournit un comportement de sauvegarde si __str__
est manquant.
Donc on devrait d'abord écrire un __repr__
qui vous permet de réinstenter un objet équivalent à partir de la chaîne de caractères qu'il renvoie, par exemple en utilisant eval
ou en le tapant dans caractère pour 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 passez à format
, str.format
, ou str
, alors si un __str__
la méthode est définie, cette méthode sera appelée, sinon, __repr__
sera utilisé.
__repr__
la méthode __repr__
est appelée par la fonction repr
et est ce qui se répercute sur votre shell python quand il évalue une expression qui renvoie un objet.
Puisqu'il fournit une sauvegarde pour __str__
, si vous pouvez n'en écrire qu'un, en commençant 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 pouvoir créer un objet équivalent. mais ce n'est pas l'implémentation par défaut.
mise en œuvre par défaut de __repr__
l'objet par défaut __repr__
est ( C source Python ) quelque chose comme:
def __repr__(self):
return '<{0}.{1} object at {2}>'.format(
self.__module__, type(self).__name__, hex(id(self)))
qui signifie par défaut que vous imprimerez le module d'où provient l'objet, le nom de 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éduire comment on pourrait créer avec précision une représentation canonique d'une instance donnée, et c'est mieux que rien, au moins nous disant comment nous pourrions l'identifier de façon unique dans la mémoire.
comment __repr__
peut-il être utile?
regardons à quel point il peut être utile, en utilisant le shell Python et les objets datetime
. Tout d'abord, nous devons 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. Il 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 format agréable lisible par l'homme (en fait, ISO). Ceci est implémenté par __str__
de datetime:
>>> 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 collant à partir de la sortie __repr__
, 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 mettre en œuvre?
pendant que vous développez, vous voudrez être en mesure 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__
( Python source ). Il est assez complexe, parce que 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__
suivant. 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__
?
c'est une critique d'une autre réponse ici qui suggère de mettre __repr__ = __str__
.
réglage __repr__ = __str__
est stupide - __repr__
est un repli pour __str__
et un __repr__
, écrits pour l'usage des développeurs dans le débogage, devraient être écrits avant d'écrire un __str__
.
Vous avez besoin d'un __str__
seulement quand vous avez besoin d'une représentation textuelle de l'objet.
Conclusion
définir __repr__
pour les objets que vous écrivez de sorte que vous et d'autres développeurs ont un exemple reproductible lorsque vous l'utilisez que vous développez. Définir __str__
quand vous avez besoin d'un lisible par l'homme représentation sous forme de chaîne.
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 object with print statement.
3) si __str__
est manquant, alors imprimer et toute fonction utilisant str()
invoque __repr__()
de l'objet.
4) __str__()
de conteneurs, lorsqu'il est invoqué exécutera __repr__()
méthode de ses éléments contenus.
5) str()
appelé dans __str__()
pourrait potentiellement se reproduire sans un cas de base, et erreur sur la profondeur de récursion maximale.
6) __repr__()
peut appeler repr()
qui tentera d'éviter la récursion infinie automatiquement, en remplaçant un objet déjà représenté par ...
.
À la page 358 du livre script Python pour le calcul de la science par Hans Petter Langtangen, il indique clairement que
- le
__repr__
vise une représentation en chaîne complète de l'objet; - le
__str__
est de retourner une belle corde pour l'impression.
donc, je préfère les comprendre comme
- repr = reproduire
- str = chaîne de caractères (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'
En toute honnêteté, eval(repr(obj))
n'est jamais utilisé. Si vous vous trouvez à l'utiliser, vous devez arrêter, car eval
est dangereux, et les chaînes de caractères sont un moyen très inefficace de sérialiser vos objets (utilisez pickle
à la place).
par conséquent, je recommande le réglage __repr__ = __str__
. La raison en est que str(list)
appelle repr
sur les éléments (je considère que c'est l'un des plus gros défauts de conception de Python qui n'a pas été abordé par Python 3). Un le repr
réel ne sera probablement pas très utile comme la sortie de print [your, objects]
.
pour qualifier ceci, d'après mon expérience, le cas d'utilisation le plus utile de la fonction repr
est de mettre une chaîne dans une autre chaîne (en utilisant le 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 montrer une représentation en chaîne de votre objet à lire facilement par d'autres.
__repr__
est utilisé pour montrer une représentation en chaîne de l'objet .
disons que je veux créer une classe Fraction
où la représentation string d'une fraction est '(1/2) ' et l'objet (Classe Fraction) doit être représenté comme 'Fraction (1,2) '
pour que nous puissions créer une classe de 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)
à Partir de http://pyref.infogami.com/__str__ par effbot:
__str__
" calcule la représentation de chaîne "informelle" d'un objet. Ceci diffère de __repr__
en ce qu'il n'est pas nécessaire que ce soit une expression valide de Python: une représentation plus pratique ou concise peut être utilisée à la place."
Un aspect qui manque dans les autres réponses. C'est vrai qu'en général, le modèle est:
- le But de
__str__
: lisible par l'homme - but de
__repr__
: non ambigu, peut-être lisible par machine viaeval
malheureusement, cette différenciation est imparfaite, car le REPL Python et aussi IPython utilisent __repr__
pour imprimer des objets dans une console REPL (voir questions connexes pour Python et IPython ). Ainsi, les projets qui sont ciblés pour le travail sur console interactive (par exemple, Numpy ou Pandas) ont commencé à ignorer les règles ci-dessus et à fournir une implémentation __repr__
lisible par l'humain à la place.
str
- Crée un nouvel objet string à partir de l'objet donné.
repr
- renvoie la représentation canonique de l'objet.
les différences:
str ():
- rend l'objet lisible
- génère la sortie pour l'utilisateur final
repr ():
- a besoin d'un code qui reproduit l'objet
- génère la sortie pour le développeur
excellentes réponses couvrent déjà la différence entre __str__
et __repr__
, qui pour moi se résume à la première étant lisible même par un utilisateur final, et le dernier étant aussi utile que possible pour les développeurs. Étant donné que, je trouve que l'implémentation par défaut de __repr__
échoue souvent à atteindre cet objectif parce qu'il omet informations utiles aux développeurs.
Pour cette raison, si j'ai un assez simple __str__
, je généralement juste essayer 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')
quand print() est appelé sur le résultat de décimal.Décimal(23) / décimal.Décimal ("1.05") le nombre brut est imprimé; cette sortie est en string form qui peut être atteint avec __str __(). Si nous entrons simplement l'expression nous obtenons une décimale.Sortie décimale-cette sortie est dans la forme de représentation qui peut être réalisée avec __repr __(). Tous les objets Python ont deux formes de sortie. La forme de chaîne de caractères 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éteur Python, produirait (si possible) à nouveau l'objet représenté
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 favorise sans ambiguïté sur la lisibilité , le __str__
appel d'un tuple
appelle les objets contenus " __repr__
, le " formel " représentation d'un objet. Bien que la représentation formelle est plus difficile à lire qu'un informel, il est sans ambiguïté et plus robuste contre les bugs.
"A basic requirement for a Python object is to provide usable
string representations of itself, one used for debugging and
logging, another for presentation to end users. That is why the
special methods __repr__ and __str__ exist in the data model."
du livre: Fluent Python
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'
Comprendre __str__
et __repr__
intuitivement et de manière permanente les distinguer.
__str__
retourner la chaîne de caractères corps déguisé d'un objet donné pour lisibilité d'yeux
__repr__
retourner le corps de chair réel d'un objet donné (retourner lui-même) pour identifier 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
comme __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 faire une opération arithmétique sur __repr__
résultats commodément.
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 s'applique 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 que l'erreur.
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
espérons que cela vous aidera à construire des bases concrètes pour explorer plus de réponses.
tellement plus clair de blog
str est comme toString. créé pour que vous puissiez imprimer les données repr , c'est comme sérialiser, ou de la saumure. Comment puis-je recréer cet objet si je dois 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))
__repr__
est utilisé partout, sauf par print
et str
lorsqu'un __str__
est défini