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

Для чего используется @property в Python?

2.0 Middle🔥 241 комментариев
#Python Core#Архитектура и паттерны

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

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

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

Декоратор @property в Python

@property — мощный инструмент для создания управляемых атрибутов класса. Он позволяет вызывать методы как свойства, сохраняя возможность добавить логику при доступе.

Основная идея

Без @property нужно было бы писать getters и setters как в Java:

# ❌ Плохо — verbose, не pythonic
class Person:
    def __init__(self, age):
        self._age = age
    
    def get_age(self):
        return self._age
    
    def set_age(self, value):
        if value < 0:
            raise ValueError("Age cannot be negative")
        self._age = value

person = Person(25)
print(person.get_age())  # Неудобно
person.set_age(26)       # Неудобно

С @property код становится чище:

# ✅ Хорошо — pythonic, добавляем логику без изменения интерфейса
class Person:
    def __init__(self, age):
        self._age = age
    
    @property
    def age(self):
        """Getter для возраста"""
        return self._age
    
    @age.setter
    def age(self, value):
        """Setter с валидацией"""
        if value < 0:
            raise ValueError("Age cannot be negative")
        self._age = value
    
    @age.deleter
    def age(self):
        """Deleter если нужно удалить"""
        del self._age

person = Person(25)
print(person.age)   # 25 — выглядит как атрибут
person.age = 26     # Вызывает setter с валидацией

Основные преимущества

1. Изменение реализации без изменения API

class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius
    
    @property
    def celsius(self):
        return self._celsius
    
    @celsius.setter
    def celsius(self, value):
        self._celsius = value
    
    @property
    def fahrenheit(self):
        """Вычисляемое свойство"""
        return self._celsius * 9/5 + 32

temp = Temperature(0)
print(temp.fahrenheit)  # 32 — вычисляется на лету
temp.celsius = 100
print(temp.fahrenheit)  # 212

Если завтра захотите добавить кэширование или логирование, это не потребует изменения кода, вызывающего температуру.

2. Валидация данных

class Rectangle:
    def __init__(self, width, height):
        self._width = width
        self._height = height
    
    @property
    def width(self):
        return self._width
    
    @width.setter
    def width(self, value):
        if value <= 0:
            raise ValueError("Width must be positive")
        self._width = value

rect = Rectangle(10, 20)
rect.width = -5  # ❌ ValueError: Width must be positive

3. Computed properties (вычисляемые атрибуты)

class User:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name
    
    @property
    def full_name(self):
        """Автоматически создаётся из first и last name"""
        return f"{self.first_name} {self.last_name}"
    
    @full_name.setter
    def full_name(self, value):
        self.first_name, self.last_name = value.split()

user = User("John", "Doe")
print(user.full_name)  # "John Doe"
user.full_name = "Jane Smith"
print(user.first_name)  # "Jane"

4. Ленивая загрузка (lazy loading)

class DataSource:
    def __init__(self, url):
        self.url = url
        self._data = None
    
    @property
    def data(self):
        """Загружаем данные только при первом доступе"""
        if self._data is None:
            print(f"Loading data from {self.url}...")
            self._data = fetch_from_api(self.url)  # Дорогая операция
        return self._data

ds = DataSource("https://api.example.com/data")
# data не загружена
print(ds.data)  # Загрузится здесь
print(ds.data)  # Вернёт кэшированный результат

@property vs обычные методы

# @property — если это логичнее рассматривать как атрибут
user.full_name

# Метод — если это явно операция/действие
user.get_profile()   # Загружает профиль с сервера
user.save()          # Сохраняет в БД

Когда не использовать @property

# ❌ Плохо — дорогая операция скрыта
@property
def heavy_computation(self):
    """Вычисление занимает 10 секунд!"""
    time.sleep(10)
    return 42

# ✅ Лучше сделать явным методом
def compute_heavy(self):
    """Явно видно, что это дорогая операция"""
    time.sleep(10)
    return 42

Итог

@property в Python — инструмент для:

  • Инкапсуляции с валидацией
  • Вычисляемых атрибутов
  • Ленивой загрузки данных
  • Изменения реализации без изменения API

Это делает код более читаемым и гибким.

Для чего используется @property в Python? | PrepBro