Ваш браузер устарел. Рекомендуем обновить его до последней версии.

Info Board


DOCUMENTATION:

@property >>

@staticmethod >>

@classmethod >>

Популярные встроенные декораторы в Python

Опубликовано 13.10.2023

Декораторы в программировании — это мощный инструмент, который позволяет добавлять новую функциональность к уже существующему коду, не изменяя его структуру. Рассмотрим в этом блоге наиболее популярные и широко используемые декораторы в разработке на Python, такие как @property, @staticmethod и @classmethod...

@property - один из наиболее распространенных декораторов в Python, который позволяет управлять доступом к атрибутам класса и обеспечивает контроль над чтением, записью и удалением значений этих атрибутов. Вот несколько примеров, как можно использовать декоратор @property на практике:

1. Getter и setter для ограничения значения атрибута.

Геттеры (getter) - это функции, которые используются для получения значения атрибута объекта. Они обычно называются в формате get_<атрибут>, например get_width или get_height. Геттеры могут быть полезны, когда нужно ограничить доступ к значению атрибута или выполнить какую-то логику перед его получением. 

Сеттеры (setter) - это функции, которые используются для установки значения атрибута объекта. Они обычно называются в формате set_<атрибут>, например set_width или set_height. Сеттеры могут быть полезны, когда нужно добавить проверку на валидность значения атрибута или выполнить какую-то логику перед его установкой.

Декораторы могут быть использованы для прикрепления геттеров и сеттеров к методам класса или для их создания через свойства (properties).

Пример использования декораторов для создания геттеров и сеттеров для атрибутов width и height:

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:
self._width = value
else:
raise ValueError("Ширина должна быть положительным числом")

@property
def height(self):

return self._height

@height.setter
def height(self, value):

if value > 0:
self._height = value
else:
raise ValueError("Высота должна быть положительным числом")

В этом примере мы используем декоратор @property, чтобы создать "геттеры" и "сеттеры" для атрибутов width и height класса Rectangle. Декоратор @width.setter позволяет нам применить проверку на положительное значение при установке нового значения для ширины прямоугольника. Аналогично, декоратор @height.setter применяет проверку на положительное значение при установке нового значения для высоты прямоугольника.

2. Создание вычисляемого атрибута.

class Circle:
def __init__(self, radius):
self._radius = radius

@property
def diameter(self):

return self._radius * 2

@property
def circumference(self):

return 2 * 3.14159 * self._radius

@property
def area(self):

return 3.14159 * self._radius ** 2

# Создаем экземпляр класса
circles = Circle(2)
# Вызываем метод area() через экземпляр класса

print(circles.area)

В этом примере мы используем декоратор @property, чтобы создать вычисляемые атрибуты diameter, circumference и area для класса Circle. Каждый из этих атрибутов вычисляется на основе значения атрибута radius. Когда мы обращаемся к этим атрибутам, как к обычным атрибутам класса circle, они автоматически вычисляются с помощью методов, помеченных декоратором @property.

3. Защита от нежелательных изменений атрибута.

class BankAccount:
def __init__(self, balance):
self._balance = balance

@property
def balance(self):

return self._balance

@balance.setter
def balance(self, value):

raise AttributeError("Невозможно установить баланс напрямую. \
Вместо этого используйте методы депозита или вывода средств."
)

def deposit(self, amount):
self._balance += amount

def withdraw(self, amount):
if self._balance >= amount:
self._balance -= amount
else:
raise ValueError("Недостаточно средств!")

В этом примере мы используем декоратор @property, чтобы предотвратить изменение атрибута balance напрямую. Вместо этого, мы определяем методы deposit и withdraw, которые позволяют изменять баланс счёта путём добавления или удаления денежных средств. При попытке установить значение атрибута balance напрямую, будет возбуждено исключение AttributeError.


@staticmethod - это встроенный декоратор в Python, который применяется к методу внутри класса и обозначает его статическим методом. Статический метод является методом класса, который не требует доступа к атрибутам экземпляра класса или его состоянию и может вызываться самим классом, а не только его экземплярами. Одно из главных преимуществ статических методов заключается в том, что они могут быть вызваны без создания экземпляра класса.

Ниже приведём несколько наиболее часто применяемых примеров использования декоратора @staticmethod:

1. Математические операции:

class MathUtils:
@staticmethod
def add_nums(x, y):

return x + y

result = MathUtils.add_nums(5, 3)
print(result) # Вывод: 8

В данном примере статический метод add_nums выполняет простое сложение двух чисел. Нет необходимости создавать экземпляр класса MathUtils. Таким образом, использование @staticmethod позволяет нам определить функцию внутри класса, которая не зависит от состояния экземпляра и не требует доступа к его атрибутам. При создании экземпляра класса в Python, выделяется память и инициализируются атрибуты объекта. В отличие от обычных методов, внутри статического метода нет доступа к атрибутам экземпляра. Он работает только с аргументами, переданными ему явно.

⚠️Декоратор @staticmethod, по умолчанию, используется для методов, которые не требуют доступа к атрибутам экземпляра. Однако, если метод зависит от атрибутов экземпляра или использует его состояние, то будет необходимо создать экземпляр класса и вызывать метод через него. В таких случаях использование @staticmethod будет неприменимо, так как этот декоратор ограничивает доступ к атрибутам экземпляра.

2. Вспомогательные функции:

class StringUtils:
@staticmethod
def is_palindrome(word):

word = word.lower()
return word == word[::-1]

result = StringUtils.is_palindrome("radar")
print(result) # Вывод: True

Здесь статический метод is_palindrome проверяет является ли переданное слово палиндромом. Метод не требует доступа к атрибутам класса или экземпляра.

3. Встроенные методы:

Встроенный метод - это шаблон проектирования, который предоставляет интерфейс для создания объектов некоторого класса, но оставляет конкретную реализацию создания объекта на усмотрение подклассов. Встроенный метод отражает идею создания объектов с использованием метода, но без необходимости создавать экземпляр класса, как это происходит с обычными методами. Например:

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

@staticmethod
def create_rectangle(width, height):

return Shape(width, height)

rectangle = Shape.create_rectangle(4, 5)
print(rectangle.x, rectangle.y) # Вывод: 4, 5

Здесь статический метод create_rectangle является встроенным методом, который создаёт экземпляр класса Shape с заданными параметрами width и height.

Все приведенные примеры демонстрируют простое использование декоратора @staticmethod для определения статических методов внутри классов. Статические методы полезны, когда внутри метода не требуется доступ к атрибутам экземпляра класса или его состоянию, и метод может быть вызван непосредственно через класс без создания экземпляра.


@classmethod - это встроенный декоратор в Python, который применяется к методу внутри класса и обозначает его классовым методом. Классовый метод принимает первым аргументом ссылку на сам класс (обычно это "cls") вместе с аргументами метода. Он может быть вызван как через класс, так и через его экземпляры. Главное отличие классового метода от обычного метода заключается в том, что классовый метод имеет доступ к атрибутам класса, а не к его экземплярам.

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

Использование декоратора @classmethod помогает создать более гибкую и модульную структуру классов в Python, позволяя выполнять операции, относящиеся к самому классу, а не к конкретным экземплярам. Ниже приведены наиболее часто применяемые примеры использования декоратора @classmethod:

1. Встроенные методы:

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

@classmethod
def create_rectangle(cls, width, height):
return cls(width, height)


rectangle = Shape.create_rectangle(4, 5)
print(rectangle.x, rectangle.y) # Вывод: 4, 5

Здесь классовый метод create_rectangle является встроенным методом, который создаёт экземпляр класса Shape с заданными параметрами width и height. Вместо явного указания класса Shape, мы используем аргумент cls, который автоматически получает ссылку на текущий класс при вызове метода через класс.

2. Создание альтернативных конструкторов:

import datetime

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

@classmethod
def from_birth_year(cls, name, birth_year):

age = datetime.date.today().year - birth_year
return cls(name, age)

person = Person.from_birth_year("Agee", 1981)
print(person.age) # Вывод: текущий возраст

В этом примере классовый метод from_birth_year служит альтернативным конструктором, который позволяет создавать экземпляры класса Person на основе имени и года рождения. Метод автоматически вычисляет возраст на основе текущего года и передает его в основной конструктор класса.

3. Вспомогательные методы:

class FileUtils:
@classmethod
def get_file_extension(cls, filename):

return filename.split(".")[-1].lower()

extension = FileUtils.get_file_extension("example.py")
print(extension) # Вывод: "py"

В этом примере классовый метод get_file_extension является вспомогательным методом, который получает расширение файла на основе его имени. Метод не требует доступа к атрибутам экземпляра класса и может быть вызван непосредственно через класс.

Все приведенные примеры демонстрируют использование декоратора @classmethod для определения классовых методов внутри классов. Классовые методы полезны, когда требуется доступ к атрибутам класса или необходимость в создании альтернативных конструкторов или вспомогательных методов, которые могут быть вызваны как через класс, так и через его экземпляры.


Создание экземпляра класса в Python имеет несколько важных причин и позволяет использовать возможности объектно-ориентированного программирования. Вот несколько причин, почему нужно создавать экземпляр класса:

1. Хранение состояния: Экземпляр класса позволяет создавать объекты, которые могут хранить свое состояние в виде атрибутов. Вы можете использовать атрибуты для хранения и обработки данных, которые относятся к этому конкретному экземпляру. Каждый экземпляр класса имеет свое собственное состояние, что позволяет создавать множество объектов с разными значениями атрибутов.

2. Инкапсуляция: Создание экземпляра класса позволяет использовать приватные атрибуты и методы, которые могут быть доступны только внутри экземпляра. Это обеспечивает инкапсуляцию данных и функциональности, что способствует более чистому и понятному коду.

3. Поддержка наследования: Создание экземпляра класса позволяет использовать наследование — механизм, который позволяет одному классу наследовать атрибуты и методы другого класса. Это позволяет создавать иерархии классов и дает возможность переопределять или расширять функциональность базовых классов.

4. Группировка функциональности: Создание экземпляра класса позволяет группировать связанные методы и данные в единый объект. Это позволяет логически организовывать код и упрощает понимание и использование сложных систем.

5. Полиморфизм: Создание экземпляра класса позволяет использовать полиморфизм — способность объекта иметь разные формы. Это позволяет вызывать один и тот же метод на разных экземплярах класса, но каждый экземпляр может реагировать на него по-разному в зависимости от своей реализации.