Управление печатью экземпляров класса

Раздел: Основы Python -> Объектно-ориентированное программирование

Настройка печати объектов класса

Наиболее эффективный способ задать вывод экземпляра класса при вызове print() или str() - переопределить магический метод __str__. Для целей отладки и для представления, возвращаемого repr(), следует также определить __repr__. Эти методы возвращают строку, которая и будет отображаться.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f"Person({self.name}, {self.age})"

    def __repr__(self):
        return f"Person(name={self.name!r}, age={self.age!r})"

p = Person("Alice", 30)
print(p)          # Person(Alice, 30)
print(repr(p))    # Person(name='Alice', age=30)

атрибуты класса python (атрибуты классов и объектов в python)

Person(Alice, 30)
Person(name='Alice', age=30)

библиотека классов python (библиотека классов в python)

Типичная ошибка: не переопределить ни один из методов, тогда print() выведет нечто вроде <__main__.Person object at 0x...>, что бесполезно для человека. Также опасно забыть вернуть строку - если метод возвращает другой тип, возникнет исключение TypeError.

Как вывести объект для разработчика?

Если требуется получить максимально полную информацию, включая типы данных, используйте __repr__. По соглашению, результат __repr__ должен быть таким, чтобы его можно было скопировать и создать аналогичный объект (если возможно).

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Point(x={self.x!r}, y={self.y!r})"

pt = Point(3.5, 2.0)
print(repr(pt))

метод объекта python (методы объектов в python)

Point(x=3.5, y=2.0)

метод call python (метод __call__ в python)

Если __repr__ не определён, используется реализация из object, которая выводит имя класса и адрес в памяти. Для отладки это неинформативно.

Как вывести объект для пользователя?

Для дружественного пользователю представления предназначен __str__. Он вызывается функциями print() и str(). Если __str__ не задан, Python использует __repr__ как запасной вариант.

class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author

    def __str__(self):
        return f"«{self.title}» ({self.author})"

b = Book("1984", "George Orwell")
print(b)

Python структура объекта (структура объекта в python)

«1984» (George Orwell)

Python создание объектов (создание объектов в python)

Часто начинающие определяют только __str__, но забывают про __repr__. Это приводит к тому, что в списках или при логировании объекты отображаются нечитаемо (так как для контейнеров вызывается __repr__).

Как отформатировать объект с помощью f-строк или метода format?

Метод __format__ позволяет управлять отображением при использовании спецификаций формата, например {0:20s}.

class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    def __str__(self):
        return f"{self.name}: ${self.price:.2f}"

    def __format__(self, spec):
        if spec == 'short':
            return self.name
        elif spec == 'long':
            return f"Product({self.name!r}, {self.price!r})"
        return str(self)

prod = Product("Laptop", 1299.99)
print(f"{prod:short}")
print(f"{prod:long}")

Self object python (объект self в python)

Laptop
Product('Laptop', 1299.99)

Object attribute python (атрибуты объекта в python)

Без определения __format__ пользовательские спецификации приводят к ошибке TypeError.

Как автоматически получить читаемый вывод с помощью dataclass?

Декоратор @dataclass автоматически генерирует __repr__ (и при необходимости __str__), что избавляет от ручного написания.

from dataclasses import dataclass

@dataclass
class Employee:
    name: str
    salary: float

emp = Employee("Bob", 50000.0)
print(emp)

Python call method (вызов метода в python)

Employee(name='Bob', salary=50000.0)

Python класс данных (класс данных в python)

Если в dataclass есть поля с большими объёмами данных, автоматический __repr__ может стать излишне подробным. В таких случаях можно переопределить метод вручную.

Как вывести объект в красиво отформатированном виде с pprint?

Модуль pprint использует __repr__ для каждого элемента. Для вложенных структур это даёт аккуратный вывод с отступами.

from pprint import pprint

class Node:
    def __init__(self, value, children=None):
        self.value = value
        self.children = children or []

    def __repr__(self):
        return f"Node({self.value!r}, children={self.children!r})"

tree = Node(1, [Node(2), Node(3, [Node(4)])])
pprint(tree)

Class method python (методы классов в python)

Node(1, children=[Node(2, children=[]), Node(3, children=[Node(4, children=[])])])

Python object methods (методы объектов в python)

pprint не работает, если __repr__ возвращает очень длинные строки без разбивки. В таких случаях помогает pprint.PrettyPrinter с настройкой ширины.

Как сериализовать объект в JSON для вывода?

Если нужно вывести объект в формате JSON, следует сначала преобразовать его в словарь (через __dict__ или кастомный метод), а затем использовать json.dumps с параметром default.

import json

class Car:
    def __init__(self, make, model):
        self.make = make
        self.model = model

    def to_dict(self):
        return {"make": self.make, "model": self.model}

car = Car("Tesla", "Model 3")
print(json.dumps(car.to_dict(), indent=2))

класс python определение (определение классов в python)

{
  "make": "Tesla",
  "model": "Model 3"
}

Self method python (параметр self в методах python)

Попытка напрямую передать объект в json.dumps вызывает TypeError: Object of type Car is not JSON serializable. Необходимо обеспечить сериализуемость.

Как вручную сформировать вывод, обращаясь к атрибутам?

Иногда проще не переопределять магические методы, а написать отдельную функцию или метод, который возвращает нужную строку. Это удобно, когда формат зависит от контекста.

class Student:
    def __init__(self, name, grades):
        self.name = name
        self.grades = grades

    def display(self, detailed=False):
        if detailed:
            return f"{self.name}: {', '.join(str(g) for g in self.grades)}"
        return self.name

s = Student("Kate", [85, 92, 78])
print(s.display())
print(s.display(detailed=True))

приватные атрибуты python (приватные атрибуты в python)

Kate
Kate: 85, 92, 78

При таком подходе теряется интеграция со стандартными функциями вроде print() и str(). Необходимо явно вызывать кастомный метод.

Выбор конкретного варианта зависит от цели: для отладки - __repr__, для пользователя - __str__, для сериализации - JSON, для красивого отображения вложенных структур - pprint.

- тип данных класса python (тип данных класса в python)
- типы методов python (типы методов в python)
- Get set python (геттеры и сеттеры в python)

Расширенные примеры печати классов

Вложенные объекты с __repr__ и ограничение глубины через reprlib

Пример
import reprlib

class Folder:
    def __init__(self, name, subfolders=None):
        self.name = name
        self.subfolders = subfolders or []

    def __repr__(self):
        subs = reprlib.repr(self.subfolders)
        return f"Folder({self.name!r}, subfolders={subs})"

root = Folder("root", [Folder("docs", [Folder("notes")]), Folder("assets")]*10)
print(repr(root))
Folder('root', subfolders=[Folder('docs', subfolders=[Folder('notes', subfolders=[])]), Folder('assets', subfolders=[]), ... (18 more)])

Многострочный __str__ с выравниванием

Пример
class Table:
    def __init__(self, rows):
        self.rows = rows  # список списков

    def __str__(self):
        lines = []
        for row in self.rows:
            lines.append(' | '.join(str(cell) for cell in row))
        return '\n'.join(lines)

t = Table([["Name", "Age"], ["Alice", 30], ["Bob", 25]])
print(t)
Name | Age
Alice | 30
Bob | 25

Кастомный JSON encoder с заменой __repr__ для сериализации

Пример
import json

class Color:
    def __init__(self, r, g, b):
        self.r = r
        self.g = g
        self.b = b

    def __repr__(self):
        return f"Color(r={self.r}, g={self.g}, b={self.b})"

class ColorEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Color):
            return {'r': obj.r, 'g': obj.g, 'b': obj.b}
        return super().default(obj)

c = Color(255, 0, 0)
print(json.dumps(c, cls=ColorEncoder))
{"r": 255, "g": 0, "b": 0}

Использование rich для цветного и структурированного вывода

Пример
from rich.console import Console
from rich.table import Table as RichTable

class Project:
    def __init__(self, name, tasks):
        self.name = name
        self.tasks = tasks

    def __rich__(self):
        table = RichTable(title=self.name)
        table.add_column("Task")
        table.add_column("Status")
        for t, s in self.tasks:
            table.add_row(t, s)
        return table

console = Console()
proj = Project("Deploy", [("build", "done"), ("test", "in progress")])
console.print(proj)
(выводится таблица с заголовком "Deploy" и двумя колонками)

Применение tabulate для табличного вывода атрибутов объектов

Пример
from tabulate import tabulate

class Record:
    def __init__(self, key, value):
        self.key = key
        self.value = value

records = [Record("alpha", 1), Record("beta", 2)]
headers = ["Key", "Value"]
rows = [(r.key, r.value) for r in records]
print(tabulate(rows, headers=headers))
Key      Value
------  -------
alpha         1
beta          2

Переопределение __bytes__ для двоичного представления

Пример
class Packet:
    def __init__(self, data):
        self.data = data

    def __bytes__(self):
        return bytes(self.data, 'utf-8')

p = Packet("Hello")
print(bytes(p))
b'Hello'

Эти примеры демонстрируют гибкость Python при настройке вывода объектов. Выбор подхода зависит от контекста: краткость для консоли, структурированность для отладки, сериализация для обмена данными.

Печать класса в Python - comments

En
Python print class (python)