Декоратор свойств @property в Python
В этом уроке вы узнаете о декораторе свойств в Python (@property) и о том, как он работает.
Что такое декоратор свойств в Python?
Ранее вы узнали, как использовать класс свойств для добавления свойства в класс. Вот синтаксис класса property:
class property(fget=None, fset=None, fdel=None, doc=None)
Ниже определяется класс Person с двумя атрибутами name и age:
class Person: def __init__(self, name, age): self.name = name self.age = age
Чтобы определить метод получения для атрибута age, вы используете класс property следующим образом:
class Person: def __init__(self, name, age): self.name = name self._age = age def get_age(self): return self._age age = property(fget=get_age)
Свойство принимает геттер и возвращает объект свойства.
Следующий пример создает экземпляр класса Person и получает значение свойства age через экземпляр:
john = Person('John', 25) print(john.age)
Выход:
25
Кроме того, вы можете напрямую вызвать метод get_age() объекта Person следующим образом:
print(john.get_age())
Таким образом, чтобы получить возраст объекта Person, вы можете использовать либо свойство age, либо метод get_age().
Чтобы избежать дублирования, вы можете переименовать метод get_age() в метод age() следующим образом:
class Person: def __init__(self, name, age): self.name = name self._age = age def age(self): return self._age age = property(fget=age)
Property() принимает вызываемый объект(age) и возвращает вызываемый объект. Следовательно, это декоратор. Поэтому вы можете использовать декоратор @property для оформления метода age() следующим образом:
class Person: def __init__(self, name, age): self.name = name self._age = age @property def age(self): return self._age
Таким образом, используя декоратор @property, вы можете упростить определение свойства класса.
Сеттер-декораторы
Следующий код добавляет метод установки (set_age) для присвоения значения атрибуту _age классу Person:
class Person: def __init__(self, name, age): self.name = name self._age = age @property def age(self): return self._age def set_age(self, value): if value <= 0: raise ValueError('The age must be positive') self._age = value
Чтобы присвоить set_age fset объекта свойства age, вы вызываете метод setter() объекта свойства age следующим образом:
class Person: def __init__(self, name, age): self.name = name self._age = age @property def age(self): return self._age def set_age(self, value): if value <= 0: raise ValueError('The age must be positive') self._age = value age = age.setter(set_age)
Метод setter() принимает вызываемый объект и возвращает другой вызываемый объект (объект свойства). Поэтому вы можете использовать декоратор @age.setter для метода set_age() следующим образом:
class Person: def __init__(self, name, age): self.name = name self._age = age @property def age(self): return self._age @age.setter def set_age(self, value): if value <= 0: raise ValueError('The age must be positive') self._age = value
Теперь вы можете изменить метод set_age() на метод age() и использовать свойство age в методе __init__():
class Person: def __init__(self, name, age): self.name = name self.age = age @property def age(self): return self._age @age.setter def age(self, value): if value <= 0: raise ValueError('The age must be positive') self._age = value
Подводя итог, вы можете использовать декораторы для создания свойства по следующему шаблону:
class MyClass: def __init__(self, attr): self.prop = attr @property def prop(self): return self.__attr @prop.setter def prop(self, value): self.__attr = value
В этом шаблоне __attr — это частный атрибут, а prop — имя свойства.
В следующем примере декораторы @property используются для создания свойств имени и возраста в классе Person:
class Person: def __init__(self, name, age): self.name = name self.age = age @property def age(self): return self._age @age.setter def age(self, value): if value <= 0: raise ValueError('The age must be positive') self._age = value @property def name(self): return self._name @name.setter def name(self, value): if value.strip() == '': raise ValueError('The name cannot be empty') self._name = value