Python __str__ i listy

107

W Javie, jeśli wywołam List.toString (), automatycznie wywoła metodę toString () dla każdego obiektu wewnątrz Listy. Na przykład, jeśli moja lista zawiera obiekty o1, o2 i o3, list.toString () wyglądałaby mniej więcej tak:

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

Czy istnieje sposób na uzyskanie podobnego zachowania w Pythonie? Zaimplementowałem metodę __str __ () w mojej klasie, ale kiedy wydrukuję listę obiektów, używając:

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

wygląda mniej więcej tak:

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

jak mogę zmusić Pythona do automatycznego wywoływania mojego __str__ dla każdego elementu na liście (lub dyktowania w tym przypadku)?

benhsu
źródło
Dla porównania istnieje PEP 3140: „str (kontener) powinien wywoływać str (pozycja), a nie repr (pozycja)” , który został odrzucony.
Alexey

Odpowiedzi:

133

Wywołanie łańcucha znaków na liście w języku Python wywołuje __repr__metodę na każdym elemencie wewnątrz. W przypadku niektórych pozycji __str__i __repr__są takie same. Jeśli chcesz takiego zachowania, zrób:

def __str__(self):
    ...
def __repr__(self):
    return self.__str__()
David Berger
źródło
7
Identyfikacja __str__z __repr__zwykle nie zgadza się z modelem danych Pythona , więc rozwiązanie do rozumienia list zaproponowane przez @ daniel-lew jest bardziej pythonowe.
Ioannis Filippidis
2
Bez argumentów. Odpowiedziałem na pytanie tak, jak zostało zadane, czyli często nowicjusz w Pythonie chce pomyśleć o problemie, ale to nie znaczy, że jest to najlepszy sposób na odpowiedź.
David Berger,
1
Python powinien być spójny ze swoim własnym modelem danych i robić to samo dla wszystkich prymitywów i agregatów.
Terrence Brannon,
2
Myślę, że domyślne zachowanie list Pythona jest po prostu błędne. Spodziewałbym się, że str()na liście wróciło str()dla każdego z poszczególnych elementów wewnątrz.
SuperGeo
21

Możesz użyć funkcji rozumienia list, aby automatycznie wygenerować nową listę z każdym elementem str () 'd:

print([str(item) for item in mylist])
Dan Lew
źródło
6
Albo po prostu print(map(str, mylist))- jest trochę krótszy
anula
4
Jednym z problemów jest to, że pozycja w mylist może być również listą
Breandán Dalton
7

Dwie proste rzeczy, które możesz zrobić, użyj mapfunkcji lub użyj zrozumienia.

Ale to daje ci listę ciągów, a nie ciąg. Musisz więc połączyć ze sobą struny.

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

lub

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

Następnie możesz wydrukować ten złożony obiekt typu string.

print 'my list is %s'%( s )
S.Lott
źródło
4

W zależności od tego, do czego chcesz użyć tego wyniku, może __repr__być bardziej odpowiednie:

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
źródło
3

Zgadzam się z poprzednią odpowiedzią dotyczącą używania w tym celu wyrażeń listowych, ale z pewnością można by to ukryć za funkcją, jeśli to właśnie ona unosi łódź.

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]

Dla zabawy utworzyłem list_str () rekurencyjnie str () wszystko zawarte na liście.

Jeremy Cantrell
źródło
+1 Jest to przydatne przy wdrażaniu __str__i __repr__osobno
vincent gravitas
0

Coś takiego?

a = [1, 2 ,3]
[str(x) for x in a]
# ['1', '2', '3']
Co on robi
źródło
0

To powinno wystarczyć.

Podczas drukowania list, a także innych klas kontenerów, zawarte w nich elementy zostaną wydrukowane przy użyciu __repr__, ponieważ __repr__mają być używane do wewnętrznej reprezentacji obiektu. Jeśli zadzwonimy: help(object.__repr__)powie nam:

Help on wrapper_descriptor:

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

A jeśli zadzwonimy help(repr), wyświetli:

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.

Jeśli __str__jest zaimplementowane dla obiektu i __repr__nie jest repr(obj), wyprowadza domyślne wyjście, tak jak print(obj)wtedy, gdy żadne z nich nie jest zaimplementowane.

Więc jedynym sposobem jest wdrożenie __repr__dla swojej klasy. Można to zrobić w następujący sposób:

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
źródło
-3

Dane wyjściowe, które otrzymujesz, to tylko nazwa modułu obiektu, nazwa klasy, a następnie adres pamięci w formacie szesnastkowym, ponieważ __repr__funkcja nie jest nadpisywana.

__str__służy do reprezentacji obiektu w postaci ciągu znaków podczas korzystania z funkcji print. Ale ponieważ drukujesz listę obiektów, a nie iterujesz po liście w celu wywołania strmetody dla każdego elementu, wypisuje reprezentację obiektów.

Aby wywołać __str__funkcję, musisz zrobić coś takiego:

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

Jeśli nadpisujesz __repr__funkcję, możesz użyć metody drukowania, tak jak poprzednio:

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

Otrzymasz wtedy „ my list is [1, 2, 3]” jako wyjście.

panagiwtis koligas
źródło
Ta odpowiedź wydaje się odpowiadać na zupełnie niepowiązane pytanie. Czy na pewno umieściłeś go we właściwym miejscu?
Blckknght
tak Blckknght ta strona, na którą chciałem odpowiedzieć, miała link do tej strony z innego postu. więc poprowadziła mnie tutaj i odpowiadam tutaj, zakładając, że facet, który zadał pytanie, przyjdzie tutaj ponownie i zobaczy moją odpowiedź ... przepraszam za niedogodności !!!
panagiwtis koligas
Jeśli drugie pytanie zostało zamknięte jako duplikat tego, to w pewnym sensie zakłada się, że istniejące tutaj odpowiedzi powinny już załatwić drugie pytanie. Jeśli tak nie jest, zamiast publikować tutaj niezrozumiałą odpowiedź, powinieneś zgłosić flagę, aby ponownie otworzyć to pytanie, a prawie na pewno zostanie ona usunięta. Możliwe, że masz coś do powiedzenia, czego nie obejmuje żadna z 8 innych odpowiedzi tutaj, ale musisz nadać jej sens w kontekście tej strony, ponieważ odpowiadasz na to pytanie. I nie publikuj dwóch identycznych odpowiedzi!
Blckknght
1
Och, chociaż teraz, gdy patrzę na to ponownie, wygląda na to, że @charliebeckwith zredagował Twój post, aby był zupełnie inny, zamiast publikować własną odpowiedź, z jakiegoś niewytłumaczalnego powodu. Normalnie nie tak działają zmiany ...
Blckknght
@blckknght Zacząłem go edytować, zanim zdałem sobie sprawę, jak błędna była odpowiedź. Całkowicie niewytłumaczalne, dlaczego kontynuowałem.
charliebeckwith