← Назад к вопросам

Как объявляется getter?

1.6 Junior🔥 161 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как объявляется getter?

Getter — это метод, который позволяет безопасно получить значение приватного атрибута объекта. В Python есть несколько способов объявления getter'ов:

1. Использование @property декоратора (современный подход)

Это самый "pythonic" способ, рекомендуемый в Python:

class Person:
    def __init__(self, age):
        self._age = age  # Приватный атрибут (условно)
    
    @property
    def age(self):
        """Getter для возраста"""
        return self._age

# Использование
person = Person(25)
print(person.age)  # 25

Преимущества:

  • Выглядит как обычный атрибут, но это метод
  • Можно добавить логику без изменения кода клиента
  • Pythonic и читаемо

2. Property с setter'ом и deleter'ом

Полная версия с контролем значений:

class BankAccount:
    def __init__(self, balance):
        self._balance = balance
    
    @property
    def balance(self):
        """Getter: получить баланс"""
        return self._balance
    
    @balance.setter
    def balance(self, value):
        """Setter: установить баланс с проверкой"""
        if value < 0:
            raise ValueError("Баланс не может быть отрицательным")
        self._balance = value
    
    @balance.deleter
    def balance(self):
        """Deleter: удалить баланс"""
        print(f"Баланс {self._balance} был удален")
        del self._balance

# Использование
account = BankAccount(1000)
print(account.balance)      # 1000 (getter)
account.balance = 1500      # 1500 (setter)
# account.balance = -100    # ValueError!
del account.balance         # Выведет: Баланс 1500 был удален

3. Простой метод getter (старый стиль, но всё ещё используется)

Просто метод с префиксом get_:

class Rectangle:
    def __init__(self, width, height):
        self._width = width
        self._height = height
    
    def get_width(self):
        """Getter для ширины"""
        return self._width
    
    def get_height(self):
        """Getter для высоты"""
        return self._height
    
    def get_area(self):
        """Вычисляемое свойство"""
        return self._width * self._height

# Использование
rectangle = Rectangle(4, 5)
print(rectangle.get_width())    # 4
print(rectangle.get_area())     # 20

Минусы:

  • Многословно
  • Не pythonic
  • Требует вызова как метод ()

4. Getter с кэшированием (вычисляется один раз)

Для дорогих операций:

class DataProcessor:
    def __init__(self, data):
        self._data = data
        self._cache = None
    
    @property
    def processed_data(self):
        """Вычисляется один раз и кэшируется"""
        if self._cache is None:
            print("Выполняю дорогую операцию...")
            self._cache = [x * 2 for x in self._data]  # Имитация обработки
        return self._cache

# Использование
processor = DataProcessor([1, 2, 3])
print(processor.processed_data)  # Выполняю дорогую операцию... [2, 4, 6]
print(processor.processed_data)  # [2, 4, 6] (без повторного вычисления)

5. Computed property (вычисляется при каждом вызове)

Для значений, зависящих от других атрибутов:

class Circle:
    def __init__(self, radius):
        self._radius = radius
    
    @property
    def radius(self):
        return self._radius
    
    @property
    def area(self):
        """Площадь вычисляется из радиуса"""
        import math
        return math.pi * self._radius ** 2
    
    @property
    def circumference(self):
        """Окружность вычисляется из радиуса"""
        import math
        return 2 * math.pi * self._radius

# Использование
circle = Circle(5)
print(f"Радиус: {circle.radius}")        # 5
print(f"Площадь: {circle.area:.2f}")     # 78.50
print(f"Окружность: {circle.circumference:.2f}")  # 31.42

6. Property с описанием и документацией

Добавляем docstring для объяснения:

class Student:
    def __init__(self, name, grades):
        self._name = name
        self._grades = grades
    
    @property
    def name(self):
        """str: Имя студента (только для чтения)"""
        return self._name
    
    @property
    def average_grade(self):
        """float: Средняя оценка студента
        
        Returns:
            float: Средняя из всех оценок
            
        Raises:
            ValueError: Если нет оценок
        """
        if not self._grades:
            raise ValueError("У студента нет оценок")
        return sum(self._grades) / len(self._grades)

# Использование с help()
help(Student.average_grade)

7. Getter с использованием getattr

Динамический доступ к атрибутам:

class DynamicObject:
    def __init__(self):
        self._data = {"name": "John", "age": 30}
    
    def __getattr__(self, name):
        """Вызывается, когда атрибут не найден"""
        if name in self._data:
            return self._data[name]
        raise AttributeError(f"Атрибут '{name}' не найден")

# Использование
obj = DynamicObject()
print(obj.name)  # "John"
print(obj.age)   # 30
# print(obj.unknown)  # AttributeError

8. Сравнение подходов

# Способ 1: @property (РЕКОМЕНДУЕТСЯ)
class UserProperty:
    def __init__(self, email):
        self._email = email
    
    @property
    def email(self):
        return self._email

user1 = UserProperty("john@example.com")
print(user1.email)  # john@example.com

# Способ 2: getter метод (старый стиль)
class UserGetter:
    def __init__(self, email):
        self._email = email
    
    def get_email(self):
        return self._email

user2 = UserGetter("jane@example.com")
print(user2.get_email())  # jane@example.com

# Способ 3: public атрибут (небезопасно)
class UserPublic:
    def __init__(self, email):
        self.email = email  # Нет защиты

user3 = UserPublic("bob@example.com")
user3.email = 123  # Кто угодно может присвоить неправильное значение

9. Getter с валидацией в setter'е

class Email:
    def __init__(self, value):
        self._email = None
        self.email = value  # Использует setter с валидацией
    
    @property
    def email(self):
        """Getter: получить email"""
        return self._email
    
    @email.setter
    def email(self, value):
        """Setter: установить email с валидацией"""
        if "@" not in value or "." not in value:
            raise ValueError(f"Некорректный email: {value}")
        self._email = value

# Использование
email = Email("user@example.com")
print(email.email)          # user@example.com
# email.email = "invalid"   # ValueError

10. Использование @functools.cached_property (Python 3.8+)

Автоматическое кэширование:

from functools import cached_property

class LargeDataProcessor:
    def __init__(self, data):
        self.data = data
    
    @cached_property
    def processed_data(self):
        """Вычисляется один раз и кэшируется навсегда"""
        print("Обрабатываю данные...")
        return [x * 2 for x in self.data]

# Использование
processor = LargeDataProcessor([1, 2, 3])
print(processor.processed_data)  # Обрабатываю данные... [2, 4, 6]
print(processor.processed_data)  # [2, 4, 6] (из кэша)

Рекомендации:

  • @property — стандартный и рекомендуемый способ в Python
  • get_ методы* — используй редко, в особых случаях
  • @cached_property — для дорогих вычислений (Python 3.8+)
  • getattr — для динамических атрибутов
  • Всегда используй _prefix — чтобы указать на "приватность"

В Python getter'ы объявляются через @property декоратор — это самый pythonic и современный способ.