Jak wydrukować instancje klasy za pomocą print ()?

538

Uczę się lin w Pythonie. Kiedy próbuję wydrukować obiekt klasy Foobarza pomocą print()funkcji, otrzymuję dane wyjściowe takie jak to:

<__main__.Foobar instance at 0x7ff2a18c>

Czy istnieje sposób, aby ustawić zachowanie drukowania (lub reprezentację ciągu ) klasy i jej obiektów ? Na przykład, gdy print()wywołuję obiekt klasy, chciałbym wydrukować jego elementy danych w określonym formacie. Jak to osiągnąć w Pythonie?

Jeśli znasz klasy C ++, powyższe można osiągnąć dla standardu ostream, dodając friend ostream& operator << (ostream&, const Foobar&)metodę dla klasy.

Ashwin Nanjappa
źródło

Odpowiedzi:

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

__str__Metody jest to, co się dzieje, kiedy go wydrukować, a __repr__metoda jest to, co się dzieje podczas korzystania z repr()funkcji (lub, jeśli spojrzeć na to z interaktywny wiersz). Jeśli nie jest to najbardziej Pythońska metoda, przepraszam, ponieważ wciąż się uczę - ale działa.

Jeśli nie __str__podano żadnej metody, Python __repr__zamiast tego wydrukuje wynik . Jeśli zdefiniujesz, __str__ale nie __repr__, Python użyje tego, co widzisz powyżej __repr__, ale nadal będzie używany __str__do drukowania.

Chris Lutz
źródło
11
istnieje również metoda Unicode , której można użyć zamiast Str ; zwróć uwagę, że powinien zwrócić obiekt Unicode, a nie ciąg znaków (ale jeśli zwrócisz ciąg znaków, konwersja na Unicode i tak zostanie wykonana ...)
kender
@kender - nie wiedziałem o tym, ale z perspektywy czasu ma to sens, biorąc pod uwagę zepsutą obsługę Unicode w Pythonie 2.x.
Chris Lutz
11
Myślę, że tej odpowiedzi nie da się uzupełnić bez linku do tej drugiej !
tnotstar 20.12.12
Uratował mnie! Jednak po ponownym wdrożeniu metody __repr __ (self), print wprowadzi użytkowników w błąd. Czy znasz jakieś najlepsze praktyki w tym zakresie?
Wietnam
10
Dla programistów Java: __str __ (self) jest jak toString () świata python
Janac Meena
134

Jak wspomniał Chris Lutz , jest to zdefiniowane przez __repr__metodę w twojej klasie.

Z dokumentacji repr():

W przypadku wielu typów ta funkcja podejmuje próbę zwrócenia ciągu, który dałby obiekt o tej samej wartości po przekazaniu eval(), w przeciwnym razie reprezentacja jest ciągiem zamkniętym w nawiasach kątowych, który zawiera nazwę typu obiektu wraz z dodatkowymi informacjami często w tym nazwa i adres obiektu. Klasa może kontrolować, co ta funkcja zwraca dla swoich instancji, poprzez zdefiniowanie __repr__()metody.

Biorąc pod uwagę następującą klasę testu:

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)

.. będzie działał w następujący sposób w powłoce Pythona:

>>> 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

Jeśli nie __str__zdefiniowano żadnej metody, print(t)(lub print(str(t))) użyje wyniku __repr__zamiast

Jeśli nie __repr__zdefiniowano żadnej metody, używana jest wartość domyślna, co jest prawie równoważne z ...

def __repr__(self):
    return "<%s instance at %s>" % (self.__class__.__name__, id(self))
dbr
źródło
+1, ale kod twojej klasy __str__różni się od wyników interaktywnej powłoki, które dajesz. : P
Chris Lutz
1
Err, oops .. ręczna modyfikacja wyniku REPL nigdy się nie kończy dobrze. Powinienem prawdopodobnie doctestować moje posty: P
dbr
1
%Formatowania ciągiem jest wycofywane z docs.python.org/whatsnew/2.6.html „operator% jest uzupełniony przez mocniejszy metodę wzoru (formatowania ciągu)”
dbr
4
Dbr: To prawda. Zwróć uwagę, że dokument „Co nowego w Pythonie 3.0” mówi także „metoda format () [...] Ostatecznie planuje się uczynić z tego jedynego API do formatowania ciągów i zacząć przestać operować operatorem% w Pythonie 3.1”.
Ashwin Nanjappa
1
Pitty, %było bardzo wygodne.
Janusz Lenar,
52

Ogólny sposób, który można zastosować do dowolnej klasy bez określonego formatowania, można wykonać w następujący sposób:

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__)

I wtedy,

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

produkuje

__main__.Element: {'symbol': 'some_symbol', 'name': 'my_name', 'number': 3}
użytkownik394430
źródło
23

Jeśli jesteś w sytuacji takiej jak @Keith, możesz spróbować:

print a.__dict__

Jest to sprzeczne z tym, co uważam za dobry styl, ale jeśli próbujesz po prostu debugować, powinno zrobić to, co chcesz.

Jan
źródło
Czy wiesz, jak się dowiedzieć, czy klucz dict ma obiekty w swoich wartościach?
pranaygoyal02
1
@HadoopEvangelist Czy pytasz, jak rekurencyjnie wydrukować te obiekty, czy po prostu ustalić, czy istnieją obiekty?
Jan
13

Aby dodać moje dwa centy do odpowiedzi @ dbr, poniżej znajduje się przykład implementacji tego zdania z oficjalnej dokumentacji, którą zacytował:

„[...], aby zwrócić ciąg, który dałby obiekt o tej samej wartości po przekazaniu do eval (), [...]”

Biorąc pod uwagę tę definicję klasy:

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)

Teraz łatwo jest serializować wystąpienie Testklasy:

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

Tak więc, uruchamiając ostatni fragment kodu, otrzymamy:

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")

Ale, jak powiedziałem w moim ostatnim komentarzu: więcej informacji jest tutaj !

tnotstar
źródło
12

Musisz użyć __repr__. Jest to standardowa funkcja jak __init__. Na przykład:

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
schemat_przepływu
źródło
2
Repr i str mają różne semantyki: repr powinna być źródłem Python, który (re) tworzą ten sam cel - to jest jego repr esentation w kodzie; str powinno być ładnym oznaczeniem obiektu dla użytkownika.
Eric Towers
12

Ładniejsza wersja odpowiedzi @ 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)

Tworzy ładną wizualnie listę nazw i wartości.

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

Jeszcze bardziej wyrafinowana wersja (dzięki Ruud) sortuje przedmioty:

def __str__(self):
    return  str(self.__class__) + '\n' + '\n'.join((str(item) + ' = ' + str(self.__dict__[item]) for item in sorted(self.__dict__)))
MikeyB
źródło
8

W przypadku Python 3:

Jeśli określony format nie jest ważny (np. Do debugowania), po prostu odziedzicz z klasy Printable poniżej. Nie trzeba pisać kodu dla każdego obiektu.

Zainspirowany odpowiedzią

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

W tym wątku jest już wiele odpowiedzi, ale żadna z nich szczególnie mi nie pomogła, sam musiałem to wypracować, więc mam nadzieję, że ta jest nieco bardziej pouczająca.

Musisz tylko upewnić się, że na końcu zajęć masz nawiasy, np .:

print(class())

Oto przykład kodu z projektu, nad którym pracowałem:

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")

Aby wydrukować moją klasę wodoru, użyłem:

print(Hydrogen())

Pamiętaj, że nie zadziała to bez nawiasów na końcu wodoru. Są konieczne.

Mam nadzieję, że to pomoże, daj mi znać, jeśli masz więcej pytań.

Krępy
źródło