Python __str__ et listes

107

En Java, si j'appelle List.toString (), il appellera automatiquement la méthode toString () sur chaque objet à l'intérieur de List. Par exemple, si ma liste contient les objets o1, o2 et o3, list.toString () ressemblerait à ceci:

"[" + o1.toString() + ", " + o2.toString() + ", " + o3.toString() + "]"

Existe-t-il un moyen d'obtenir un comportement similaire en Python? J'ai implémenté une méthode __str __ () dans ma classe, mais lorsque j'imprime une liste d'objets, en utilisant:

print 'my list is %s'%(list)

ça ressemble à quelque chose comme ça:

[<__main__.cell instance at 0x2a955e95f0>, <__main__.cell instance at 0x2a955e9638>, <__main__.cell instance at 0x2a955e9680>]

comment puis-je faire en sorte que python appelle automatiquement mon __str__ pour chaque élément de la liste (ou dict d'ailleurs)?

benhsu
la source
Juste pour référence, il y a PEP 3140: "str (container) devrait appeler str (item), pas repr (item)" , qui a été rejeté.
Alexey le

Réponses:

133

L'appel de chaîne sur une liste python appelle la __repr__méthode sur chaque élément à l'intérieur. Pour certains articles, __str__et __repr__sont les mêmes. Si vous voulez ce comportement, faites:

def __str__(self):
    ...
def __repr__(self):
    return self.__str__()
David Berger
la source
7
L'identification __str__avec __repr__n'est généralement pas conforme au modèle de données Python , donc la solution de compréhension de liste proposée par @ daniel-lew est plus pythonique.
Ioannis Filippidis
2
Aucun argument. J'ai répondu à la question telle que posée, ce qui est souvent la façon dont un nouveau venu en python veut penser au problème, mais cela ne veut pas dire que c'est la meilleure façon de répondre.
David Berger
1
Python doit être cohérent avec son propre modèle de données et faire la même chose pour toutes les primitives et agrégats.
Terrence Brannon
2
Je pense que le comportement par défaut des listes python est tout simplement faux. Je m'attendrais à ce que str()sur une liste renvoyée str()pour chacun des éléments individuels à l'intérieur.
SuperGeo
21

Vous pouvez utiliser une compréhension de liste pour générer une nouvelle liste avec chaque élément str () 'd automatiquement:

print([str(item) for item in mylist])
Dan Lew
la source
6
Ou simplement print(map(str, mylist))- c'est un tout petit peu plus court
anula
4
Un problème avec ceci est si l'élément dans ma liste peut également être une liste
Breandán Dalton
7

Deux choses simples que vous pouvez faire, utiliser la mapfonction ou utiliser une compréhension.

Mais cela vous donne une liste de chaînes, pas une chaîne. Vous devez donc également joindre les chaînes ensemble.

s= ",".join( map( str, myList ) )

ou

s= ",".join( [ str(element) for element in myList ] )

Ensuite, vous pouvez imprimer cet objet de chaîne composite.

print 'my list is %s'%( s )
S.Lott
la source
4

Selon ce que vous souhaitez utiliser cette sortie, peut __repr__-être peut-être plus approprié:

import unittest

class A(object):
    def __init__(self, val):
        self.val = val

    def __repr__(self):
        return repr(self.val)

class Test(unittest.TestCase):
    def testMain(self):
        l = [A('a'), A('b')]
        self.assertEqual(repr(l), "['a', 'b']")

if __name__ == '__main__':
    unittest.main()
Horst Gutmann
la source
3

Je suis d'accord avec la réponse précédente sur l'utilisation de la compréhension de liste pour ce faire, mais vous pouvez certainement cacher cela derrière une fonction, si c'est ce qui fait flotter votre bateau.

def is_list(value):
    if type(value) in (list, tuple): return True
    return False

def list_str(value):
    if not is_list(value): return str(value)
    return [list_str(v) for v in value]

Juste pour le plaisir, j'ai créé list_str () récursivement str () tout ce qui est contenu dans la liste.

Jeremy Cantrell
la source
+1 Ceci est utile lors de la mise en œuvre __str__et __repr__séparément
vincent gravitas
0

Quelque chose comme ça?

a = [1, 2 ,3]
[str(x) for x in a]
# ['1', '2', '3']
Que fait-il
la source
0

Cela devrait suffire.

Lors de l'impression de listes ainsi que d'autres classes de conteneurs, les éléments contenus seront imprimés en utilisant __repr__, car il __repr__est destiné à être utilisé pour la représentation d'objet interne. Si nous appelons: help(object.__repr__)cela nous dira:

Help on wrapper_descriptor:

__repr__(self, /)
    Return repr(self).

Et si nous l'appelons, help(repr)il affichera:

Help on built-in function repr in module builtins:

repr(obj, /)
    Return the canonical string representation of the object.

    For many object types, including most builtins, eval(repr(obj)) == obj.

Si __str__est implémenté pour un objet et __repr__ne l'est pas repr(obj), la sortie par défaut est générée, comme print(obj)si aucune de celles-ci n'est implémentée.

Donc, le seul moyen est de mettre en œuvre __repr__pour votre classe. Une façon possible de le faire est la suivante:

class C:           
    def __str__(self):
        return str(f"{self.__class__.__name__} class str ")

C.__repr__=C.__str__       
ci = C()    


print(ci)       #C class str 
print(str(ci))  #C class str 
print(repr(ci)) #C class str 
prosti
la source
-3

La sortie que vous obtenez est simplement le nom du module de l'objet, le nom de la classe, puis l'adresse mémoire en hexadécimal car la __repr__fonction n'est pas remplacée.

__str__est utilisé pour la représentation sous forme de chaîne d'un objet lors de l'utilisation de print. Mais puisque vous imprimez une liste d'objets et que vous n'effectuez pas une itération sur la liste pour appeler la strméthode pour chaque élément, il imprime la représentation des objets.

Pour que la __str__fonction soit appelée, vous devez faire quelque chose comme ceci:

'my list is %s' % [str(x) for x in myList]

Si vous remplacez la __repr__fonction, vous pouvez utiliser la méthode d'impression comme vous l'étiez auparavant:

class cell:
    def __init__(self, id):
        self.id = id
    def __str__(self):
        return str(self.id) # Or whatever
    def __repr__(self):
        return str(self) # function invoked when you try and print the whole list.

myList = [cell(1), cell(2), cell(3)]
'my list is %s' % myList

Ensuite, vous obtiendrez " my list is [1, 2, 3]" comme sortie.

panagiwtis koligas
la source
Cette réponse semble répondre à une question totalement indépendante. Êtes-vous sûr de l'avoir mis au bon endroit?
Blckknght
oui Blckknght cette page que je voulais donner ma réponse avait un lien vers cette page à partir d'un autre post.so cela m'a guidé ici et je réponds ici en supposant que le gars qui a posé la question reviendra ici et verra ma réponse..désolé pour l'inconvénient !!!
panagiwtis koligas
Si l'autre question a été fermée comme un double de celle-ci, il est en quelque sorte supposé que les réponses existantes ici devraient déjà prendre en charge l'autre question. Si ce n'est pas le cas, vous devriez signaler de rouvrir cette question, plutôt que d'afficher une réponse incompréhensible ici, qui sera presque certainement supprimée. Maintenant, il est possible que vous ayez quelque chose à dire qui ne soit pas couvert par l'une des 8 autres réponses ici, mais vous devrez donner un sens à votre réponse dans le contexte de cette page, puisque c'est à cette question que vous répondez. Et ne postez pas deux réponses identiques!
Blckknght
1
Oh, bien que maintenant que je la regarde à nouveau, il semble que @charliebeckwith ait modifié votre message pour qu'il soit complètement différent, plutôt que de publier sa propre réponse, pour une raison inexplicable. Ce n'est pas comme ça que les modifications fonctionnent normalement ...
Blckknght
@blckknght J'ai commencé à le modifier avant de réaliser à quel point la réponse était différente. Complètement inexplicable pourquoi j'ai continué.
charliebeck avec le