Comment imprimer des instances d'une classe en utilisant print ()?

539

J'apprends les cordes en Python. Lorsque j'essaie d'imprimer un objet de classe Foobarà l'aide de la print()fonction, j'obtiens une sortie comme celle-ci:

<__main__.Foobar instance at 0x7ff2a18c>

Existe-t-il un moyen de définir le comportement d'impression (ou la représentation sous forme de chaîne ) d'une classe et de ses objets ? Par exemple, lorsque j'appelle print()un objet de classe, je voudrais imprimer ses membres de données dans un certain format. Comment y parvenir en Python?

Si vous êtes familier avec les classes C ++, ce qui précède peut être réalisé pour la norme ostreamen ajoutant une friend ostream& operator << (ostream&, const Foobar&)méthode pour la classe.

Ashwin Nanjappa
la source

Réponses:

629
>>> class Test:
...     def __repr__(self):
...         return "Test()"
...     def __str__(self):
...         return "member of Test"
... 
>>> t = Test()
>>> t
Test()
>>> print(t)
member of Test

La __str__méthode est ce qui se passe lorsque vous l'imprimez, et la __repr__méthode est ce qui se produit lorsque vous utilisez la repr()fonction (ou lorsque vous la regardez avec l'invite interactive). Si ce n'est pas la méthode la plus Pythonique , je m'excuse, parce que j'apprends toujours aussi - mais ça marche.

Si aucune __str__méthode n'est indiquée, Python affichera le résultat de à la __repr__place. Si vous définissez __str__mais pas __repr__, Python utilisera ce que vous voyez ci-dessus comme __repr__, mais utilisera toujours __str__pour l'impression.

Chris Lutz
la source
11
il y a aussi une méthode unicode , que vous pouvez utiliser à la place de Str ; notez qu'il doit retourner un objet unicode, pas une chaîne (mais si vous retournez une chaîne, la conversion en unicode se fera quand même ...)
kender
@kender - Je ne le savais pas, mais rétrospectivement, cela est parfaitement logique étant donné la mauvaise gestion d'Unicode de Python 2.x.
Chris Lutz
11
Je pense que cette réponse ne peut pas être complétée sans lien vers cette autre !
tnotstar
M'a sauvé! Cependant, après avoir réimplémenté la méthode __repr __ (auto), print induira les utilisateurs en erreur. Êtes-vous au courant des meilleures pratiques à ce sujet?
Viet
10
Pour les programmeurs Java: __str __ (self) est comme la toString () du monde python
Janac Meena
134

Comme Chris Lutz l'a mentionné , cela est défini par la __repr__méthode de votre classe.

À partir de la documentation de repr():

Pour de nombreux types, cette fonction tente de renvoyer une chaîne qui donnerait un objet avec la même valeur lorsqu'il est transmis à 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.

Étant donné le test de classe suivant:

class Test:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __repr__(self):
        return "<Test a:%s b:%s>" % (self.a, self.b)

    def __str__(self):
        return "From str method of Test: a is %s, b is %s" % (self.a, self.b)

..il agira de la manière suivante dans le shell Python:

>>> t = Test(123, 456)
>>> t
<Test a:123 b:456>
>>> print repr(t)
<Test a:123 b:456>
>>> print(t)
From str method of Test: a is 123, b is 456
>>> print(str(t))
From str method of Test: a is 123, b is 456

Si aucune __str__méthode n'est définie,print(t) (ou print(str(t))) utilisera le résultat de la __repr__place

Si aucune __repr__méthode n'est définie, la valeur par défaut est utilisée, ce qui équivaut à peu près à ..

def __repr__(self):
    return "<%s instance at %s>" % (self.__class__.__name__, id(self))
dbr
la source
+1 mais le code de votre classe __str__est différent des résultats du shell interactif que vous donnez. : P
Chris Lutz
1
Euh, oups .. la modification manuelle de la sortie REPL ne se termine jamais bien. Je devrais probablement doctest mes messages: P
dbr
1
Le %formatage de chaîne n'est pas déconseillé, à partir de docs.python.org/whatsnew/2.6.html "l'opérateur% est complété par une méthode de formatage de chaîne plus puissante, format ()"
dbr
4
Dbr: C'est vrai. Notez que le document "Quoi de neuf dans Python 3.0" indique également "méthode format () [...] Le plan est de faire de cette application la seule API pour le formatage des chaînes et de commencer à déprécier l'opérateur% dans Python 3.1."
Ashwin Nanjappa
1
Pitty, c'est %très pratique.
Janusz Lenar
52

Une manière générique qui peut être appliquée à n'importe quelle classe sans mise en forme spécifique pourrait être effectuée comme suit:

class Element:
    def __init__(self, name, symbol, number):
        self.name = name
        self.symbol = symbol
        self.number = number

    def __str__(self):
        return str(self.__class__) + ": " + str(self.__dict__)

Et alors,

elem = Element('my_name', 'some_symbol', 3)
print(elem)

produit

__main__.Element: {'symbol': 'some_symbol', 'name': 'my_name', 'number': 3}
user394430
la source
23

Si vous êtes dans une situation comme @Keith, vous pouvez essayer:

print a.__dict__

Cela va à l'encontre de ce que je considérerais comme un bon style, mais si vous essayez simplement de déboguer, il devrait faire ce que vous voulez.

John
la source
Savez-vous comment savoir si la clé dict a des objets dans ses valeurs?
pranaygoyal02
1
@HadoopEvangelist Demandez-vous aussi comment imprimer récursivement ces objets ou simplement déterminer s'il y a des objets?
John
13

Juste pour ajouter mes deux cents à la réponse de @ dbr, voici un exemple de la façon de mettre en œuvre cette phrase à partir de la documentation officielle qu'il a citée:

"[...] pour renvoyer une chaîne qui donnerait un objet avec la même valeur une fois passé à eval (), [...]"

Compte tenu de cette définition de classe:

class Test(object):
    def __init__(self, a, b):
        self._a = a
        self._b = b

    def __str__(self):
        return "An instance of class Test with state: a=%s b=%s" % (self._a, self._b)

    def __repr__(self):
        return 'Test("%s","%s")' % (self._a, self._b)

Maintenant, il est facile de sérialiser une instance de Testclasse:

x = Test('hello', 'world')
print 'Human readable: ', str(x)
print 'Object representation: ', repr(x)
print

y = eval(repr(x))
print 'Human readable: ', str(y)
print 'Object representation: ', repr(y)
print

Donc, en exécutant le dernier morceau de code, nous obtiendrons:

Human readable:  An instance of class Test with state: a=hello b=world
Object representation:  Test("hello","world")

Human readable:  An instance of class Test with state: a=hello b=world
Object representation:  Test("hello","world")

Mais, comme je l'ai dit dans mon dernier commentaire: plus d'informations sont juste ici !

tnotstar
la source
12

Vous devez utiliser __repr__. Il s'agit d'une fonction standard comme __init__. Par exemple:

class Foobar():
    """This will create Foobar type object."""

    def __init__(self):
        print "Foobar object is created."

    def __repr__(self):
        return "Type what do you want to see here."

a = Foobar()

print a
organigramme
la source
2
repr et str ont une sémantique différente: rééd devrait être source de Python qui (re) créer le même objet - c'est sa repr esentation dans le code; str devrait être une jolie stringification de l'objet.
Eric Towers
12

Une version plus jolie de la réponse de @ user394430

class Element:
    def __init__(self, name, symbol, number):
        self.name = name
        self.symbol = symbol
        self.number = number

    def __str__(self):
        return  str(self.__class__) + '\n'+ '\n'.join(('{} = {}'.format(item, self.__dict__[item]) for item in self.__dict__))

elem = Element('my_name', 'some_symbol', 3)
print(elem)

Produit une liste visuellement agréable des noms et des valeurs.

<class '__main__.Element'>
name = my_name
symbol = some_symbol
number = 3

Une version encore plus sophistiquée (merci Ruud) trie les articles:

def __str__(self):
    return  str(self.__class__) + '\n' + '\n'.join((str(item) + ' = ' + str(self.__dict__[item]) for item in sorted(self.__dict__)))
MikeyB
la source
8

Pour Python 3:

Si le format spécifique n'est pas important (par exemple pour le débogage), héritez simplement de la classe Printable ci-dessous. Pas besoin d'écrire du code pour chaque objet.

Inspiré par cette réponse

class Printable:
    def __repr__(self):
        from pprint import pformat
        return "<" + type(self).__name__ + "> " + pformat(vars(self), indent=4, width=1)

# Example Usage
class MyClass(Printable):
    pass

my_obj = MyClass()
my_obj.msg = "Hello"
my_obj.number = "46"
print(my_obj)
PeterM
la source
1

Il y a déjà beaucoup de réponses dans ce fil mais aucune ne m'a particulièrement aidé, j'ai dû le résoudre moi-même, donc j'espère que celle-ci est un peu plus informative.

Vous devez juste vous assurer d'avoir des parenthèses à la fin de votre cours, par exemple:

print(class())

Voici un exemple de code d'un projet sur lequel je travaillais:

class Element:
    def __init__(self, name, symbol, number):
        self.name = name
        self.symbol = symbol
        self.number = number
    def __str__(self):
        return "{}: {}\nAtomic Number: {}\n".format(self.name, self.symbol, self.number

class Hydrogen(Element):
    def __init__(self):
        super().__init__(name = "Hydrogen", symbol = "H", number = "1")

Pour imprimer ma classe Hydrogène, j'ai utilisé ce qui suit:

print(Hydrogen())

Veuillez noter que cela ne fonctionnera pas sans les parenthèses à la fin de l'hydrogène. Ils sont nécessaires.

J'espère que cela vous aidera, faites-moi savoir si vous avez d'autres questions.

Courtaud
la source