Пример 1. Логирование вызовов
import logging
logging.basicConfig(
filename="functions.log",
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s",
encoding="utf-8"
)
def log_decorator(func):
def wrapper(*args, **kwargs):
logging.info(f"Функция {func.__name__} вызвана с аргументами: {args}, {kwargs}")
result = func(*args, **kwargs)
logging.info(f"Функция {func.__name__} вернула: {result}")
return result
return wrapper
@log_decorator
def add(a, b):
return a + b
@log_decorator
def say_hello():
print("Привет!")
print(add(3, 5))
say_hello()
Пояснение: декоратор записывает в файл functions.log имя функции, аргументы и результат. Обёртка принимает любые аргументы и возвращает результат, поэтому декорируемые функции работают как обычно.
Пример 2. Потеря результата в декораторе
def upper_decorator(func):
def wrapper(*args, **kwargs):
print("Выполняем функцию, но ничего не возвращаем")
func(*args, **kwargs).upper()
return wrapper
@upper_decorator
def get_text():
return "hello"
result = get_text()
print("Результат:", result)
Вывод: Результат: None. Результат вызова func не возвращается наружу, поэтому декорированная функция возвращает None.
Пример 3. Возврат результата из декоратора
def upper_decorator(func):
def wrapper(*args, **kwargs):
print("Выполняем функцию и возвращаем результат")
return func(*args, **kwargs).upper()
return wrapper
@upper_decorator
def get_text():
return "hello"
result = get_text()
print("Результат:", result)
Вывод: Результат: HELLO. Теперь обёртка возвращает преобразованный результат.
Пример 4. Проблема без functools.wraps
def simple_decorator(func):
def wrapper(*args, **kwargs):
"""Вложенная функция wrapper"""
print("\nДекорированная функция: ")
print(f"Оригинальное имя функции: {func.__name__}")
print(f"Оригинальная документация: {func.__doc__}")
return func(*args, **kwargs)
return wrapper
@simple_decorator
def example_function():
"""Это оригинальная функция."""
print("Привет!")
print("Имя декорированной функции:", example_function.__name__)
print("Документация декорированной функции:", example_function.__doc__)
example_function()
Без functools.wraps атрибуты __name__ и __doc__ принадлежат wrapper, а не оригинальной функции.
Пример 5. Решение с functools.wraps
import functools
def simple_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("\nДекорированная функция")
return func(*args, **kwargs)
return wrapper
@simple_decorator
def example_function():
"""Это оригинальная функция."""
print("Привет!")
print("Имя декорированной функции:", example_function.__name__)
print("Документация декорированной функции:", example_function.__doc__)
example_function()
Теперь метаданные оригинала сохраняются.
Пример 6. Декоратор с настраиваемым сообщением
def message_decorator(message):
def decorator(func):
def wrapper():
print(message)
return func()
return wrapper
return decorator
@message_decorator("Начинаем выполнение")
def analise_data():
print("Данные проанализированы")
@message_decorator("Загрузка данных...")
def load_data():
print("Данные загружены")
analise_data()
print()
load_data()
message_decorator — фабрика: она не оборачивает функцию сразу, а возвращает декоратор, который уже делает обёртку.
Пример 7. Автоматический retry
import time
def retry(attempts):
def decorator(func):
def wrapper(*args, **kwargs):
for i in range(attempts):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"Попытка {i+1} не удалась: {e}")
time.sleep(5)
print("Все попытки исчерпаны.")
return wrapper
return decorator
@retry(3)
def get_data(filename):
"""Читает данные из файла"""
with open(filename, "r", encoding="utf-8") as file:
return file.read()
# Для запуска создайте рядом файл data.txt
data = get_data("data.txt")
if data:
print("Содержимое файла:")
print(data)
Пример 8. Цепочка декораторов
def border_decorator(func):
def wrapper():
print("*" * 100)
func()
print("*" * 100)
return wrapper
def repeat_decorator(func):
def wrapper():
for _ in range(3):
func()
return wrapper
@border_decorator
@repeat_decorator
def print_line():
print("-" * 100)
print_line()
Сначала применяется repeat_decorator, затем border_decorator. В результате строка повторяется трижды внутри рамки.
Пример 9. Создание объектов класса Book
class Book:
def __init__(self, title, author):
self.title = title
self.author = author
book1 = Book("1984", "George Orwell")
book2 = Book("Brave New World", "Aldous Huxley")
print(book1.title, book1.author)
print(book2.title, book2.author)
Пример 10. Доступ и изменение полей
class Book:
def __init__(self, title, author):
self.title = title
self.author = author
book = Book("1984", "George Orwell")
print(book.title) # старое имя
print(book.author)
book.title = "Animal Farm" # изменение значения поля title
print(book.title) # измененное имя
Пример 11. Методы класса
class Book:
def __init__(self, title, author):
self.title = title
self.author = author
def get_description(self):
return f"{self.title} — {self.author}"
def show_info(self):
print(self.get_description())
def make_author_upper(self):
self.author = self.author.upper()
book = Book("1984", "George Orwell")
book.show_info()
book.make_author_upper()
book.show_info()
Пример 12. Класс Circle
import math
class Circle:
def __init__(self, radius):
self.radius = radius
def get_area(self):
return math.pi * self.radius ** 2
circle = Circle(5)
print(f"Площадь: {circle.get_area():.1f}")
circle.radius = 8
print(f"Новая площадь: {circle.get_area():.1f}")
Примерный вывод:
Площадь: 78.5
Новая площадь: 201.1
Как запустить в VS Code
- Создайте папку
python-fundamentals-practice/lesson-67/. - Создайте файл
summary_session_17.pyи скопируйте в него примеры. - Откройте терминал в VS Code (Ctrl + `).
- Активируйте виртуальное окружение:
venv\Scripts\activate(Windows) илиsource venv/bin/activate(Mac/Linux). - Запустите:
python summary_session_17.py