Як надрукувати екземпляри класу за допомогою print ()?


538

Я вивчаю мотузки в Python. Коли я намагаюся надрукувати об'єкт класу Foobarза допомогою print()функції, я отримую такий результат:

<__main__.Foobar instance at 0x7ff2a18c>

Чи є спосіб я встановити поведінку друку (або рядкового представлення ) класу та його об'єктів ? Наприклад, коли я закликаю print()об’єкт класу, я хотів би надрукувати його учасників даних у певному форматі. Як цього досягти в Python?

Якщо ви знайомі з класами C ++, вищезазначеного можна досягти для стандарту ostream, додавши friend ostream& operator << (ostream&, const Foobar&)метод для класу.

Відповіді:


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__Метод , що відбувається при друку, а також __repr__метод , що відбувається , коли ви використовуєте repr()функцію (або , якщо дивитися на нього з інтерактивною підказкою). Якщо це не самий пітонічний метод, я вибачаюся, тому що я все ще вчуся - але він працює.

Якщо __str__метод не вказаний, Python __repr__замість цього надрукує результат . Якщо ви визначите, __str__але ні __repr__, Python буде використовувати те, що ви бачите вище __repr__, але все-таки використовувати __str__для друку.


11
також існує метод unicode , який можна використовувати замість Str ; зауважте, що він повинен повернути об’єкт unicode, а не рядок (але якщо ви повернете рядок, перетворення в unicode все одно буде здійснено ...)
kender

@kender - Я про це не знав, але в ретроспективі це має ідеальний сенс, враховуючи зламану обробку Unicode Python 2.x.
Кріс Лутц

11
Я думаю, що ця відповідь не може бути завершена без посилання на цю іншу !
tnotstar

Врятували мене! Однак після повторної реалізації методу __repr __ (self) друк введе в оману користувачів. Чи знаєте ви якісь найкращі практики щодо цього?
В'єт,

10
Для програмістів Java: __str __ (само) - це як toString () світу пітона
Janac Meena

134

Як згадував Кріс Лутц , це визначено __repr__методом у вашому класі.

З документації repr():

Для багатьох типів ця функція робить спробу повернути рядок, який давав би об'єкту з тим же значенням при передачі eval(), інакше подання являє собою рядок, укладений у кутові дужки, який містить ім'я типу об'єкта разом з додатковою інформацією часто включаючи ім'я та адресу об’єкта. Клас може контролювати те, що ця функція повертає для своїх примірників, визначаючи __repr__()метод.

З огляду на наступний тест класу:

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)

..it буде діяти наступним чином у оболонці 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

Якщо __str__метод не визначений, print(t)(або print(str(t))) буде використовувати результат __repr__замість цього

Якщо не __repr__визначено жодного методу, тоді використовується за замовчуванням, що майже еквівалентно ..

def __repr__(self):
    return "<%s instance at %s>" % (self.__class__.__name__, id(self))

+1, але код вашого класу __str__відрізняється від результатів інтерактивної оболонки. : P
Кріс Лутц

1
Помилка, ой .. зміна виводу REPL вручну ніколи не закінчується добре. Я мушу певно doctest мої пости: P
DBR

1
%Рядок форматування не рекомендується, від docs.python.org/whatsnew/2.6.html «оператор% буде доповнений більш потужним рядки метод, формат (форматування)»
DBR

4
Dbr: Це правда. Зауважте, що документ "Що нового в Python 3.0" також говорить "format () метод [...] План полягає в тому, щоб в кінцевому підсумку зробити це єдиним API для форматування рядків, а також почати аномацію оператора% у Python 3.1."
Ешвін Нанджаппа

1
Пітті, %було дуже зручно.
Януш Ленар

52

Узагальнений спосіб, який можна застосувати до будь-якого класу без конкретного форматування, можна виконати наступним чином:

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

І потім,

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

виробляє

__main__.Element: {'symbol': 'some_symbol', 'name': 'my_name', 'number': 3}

23

Якщо у вас є така ситуація, як @Keith, ви можете спробувати:

print a.__dict__

Це суперечить тому, що я б вважав гарним стилем, але якщо ви просто намагаєтеся налагодити, то він повинен робити все, що ви хочете.


Чи знаєте ви, як дізнатися, чи має ключ dict об'єкти у своїх значеннях?
pranaygoyal02

1
@HadoopEvangelist Ви запитуєте, як рекурсивно друкувати ці об’єкти, або просто визначите, чи є об'єкти?
Джон

13

Просто для додання моїх двох центів до відповіді @ dbr, наведено приклад того, як реалізувати це речення з офіційної документації, яку він цитує:

"[...], щоб повернути рядок, який давав би об'єкт з тим же значенням при передачі в eval (), [...]"

Враховуючи це визначення класу:

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)

Тепер легко серіалізувати екземпляр Testкласу:

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

Отже, запустивши останній фрагмент коду, ми отримаємо:

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

Але, як я сказав у своєму останньому коментарі: докладніше тільки тут !


12

Вам потрібно використовувати __repr__. Це стандартна функція, як __init__. Наприклад:

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

2
магнезії і вул мають різну семантику: магнезії повинні бути Python джерелом , який буде (перо) створити один і той же об'єкт - це його магнезія esentation в коді; str повинна бути досить впорядкованою для користувача об'єктивом.
Eric Towers

12

Гарніша версія відповіді від @ 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)

Створює візуально приємний список імен та значень.

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

Рівномірна версія (спасибі Рууду) сортує елементи:

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

8

Для Python 3:

Якщо конкретний формат не важливий (наприклад, для налагодження), просто перейдіть у спадок із класу Printable нижче. Не потрібно писати код для кожного об’єкта.

Натхненний цією відповіддю

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)

1

Відповідей у ​​цій темі вже дуже багато, але жодна з них мені особливо не допомогла, мені довелося це самостійно опрацювати, тож сподіваюся, що це трохи більш інформативно.

Вам просто потрібно переконатися, що в кінці уроку є дужки, наприклад:

print(class())

Ось приклад коду з проекту, над яким я працював:

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

Для друку мого класу водню я використав наступне:

print(Hydrogen())

Зверніть увагу: це не вийде без дужок у кінці Водороду. Вони необхідні.

Сподіваюся, це допомагає, повідомте мені, якщо у вас є більше питань.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.