Обновите свою игру на Python, используя эти оболочки для максимальной эффективности и удобочитаемости.
Python, безусловно, является моим любимым языком программирования из-за его простого синтаксиса и мощных приложений в различных областях, таких как машинное обучение и веб-разработка.
Хотя я занимаюсь программированием более пяти лет, декораторы редко попадались мне на глаза, если только в этом не было крайней необходимости, например использование декоратора @staticmethod
для обозначения статического метода внутри класса.
Однако мое восприятие изменилось во время недавнего обзора мерж-реквеста, когда мой коллега представил декоратор таймера для одной из моих функций. Это пробудило во мне любопытство по поводу множества других функций, которые могут предложить декораторы, повышая чистоту и читабельность кода.
Поэтому в этой короткой статье мы рассмотрим концепцию оболочек Python и представим пять примеров, которые могут улучшить наш процесс разработки Python.
Обертки Python
Обертки Python — это функции, которые добавляются к другой функции, которая затем может добавлять дополнительные функции или изменять ее поведение без прямого изменения ее исходного кода. Обычно они реализуются как декораторы, представляющие собой специальные функции, которые принимают другую функцию в качестве входных данных и вносят некоторые изменения в ее функциональность.
Функции-обертки могут быть полезны в различных сценариях:
- Расширение функциональности. Мы можем добавить такие функции, как ведение журнала, измерение производительности или кэширование, обернув наши функции декоратором.
- Повторное использование кода: мы можем применить функцию-оболочку или даже класс к нескольким объектам, вы можете избежать дублирования кода и обеспечить согласованное поведение различных компонентов.
- Изменение поведения: мы можем перехватывать входные аргументы, например, проверять входную переменную без необходимости в большом количестве
assert
строк.
Примеры
Позвольте мне показать вам несколько примеров, которые делают обертки обязательными в нашей повседневной работе:
1 — Таймер
Эта функция-оболочка измеряет время выполнения функции и печатает прошедшее время. Это может быть полезно для профилирования и оптимизации кода.
import time def timer(func): def wrapper(*args, **kwargs): # start the timer start_time = time.time() # call the decorated function result = func(*args, **kwargs) # remeasure the time end_time = time.time() # compute the elapsed time and print it execution_time = end_time - start_time print(f"Execution time: {execution_time} seconds") # return the result of the decorated function execution return result # return reference to the wrapper function return wrapper
Чтобы создать декоратор в Python, нам нужно определить функцию с именем timer
, которая принимает параметр с именем func
, чтобы указать, что это функция декоратора. Внутри функции таймера мы определяем другую функцию с именем wrapper
, которая принимает аргументы, обычно передаваемые функции, которую мы хотим декорировать.
Внутри функции-оболочки мы вызываем нужную функцию, используя предоставленные аргументы. Мы можем сделать это с помощью строки: result = func(*args, **kwargs)
.
Наконец, функция-оболочка возвращает результат выполнения декорированной функции. Функция decorator должна возвращать ссылку на только что созданную функцию оболочки.
Чтобы использовать декоратор, вы можете применить его к нужной функции, используя символ @
.
@timer def train_model(): print("Starting the model training function...") # simulate a function execution by pausing the program for 5 seconds time.sleep(5) print("Model training completed!") train_model()
Выход:
Запуск функции обучения модели…
Обучение моделей завершено!
Время выполнения: 5,006425619125366 секунд
2 — Отладчик
Можно создать дополнительную полезную функцию-оболочку для облегчения отладки путем вывода входных и выходных данных каждой функции. Этот подход позволяет нам получить представление о потоке выполнения различных функций, не загромождая наши приложения многочисленными операторами печати.
def debug(func): def wrapper(*args, **kwargs): # print the fucntion name and arguments print(f"Calling {func.__name__} with args: {args} kwargs: {kwargs}") # call the function result = func(*args, **kwargs) # print the results print(f"{func.__name__} returned: {result}") return result return wrapper
Мы можем использовать параметры __name__
, чтобы получить имя вызываемой функции, а затем параметры args
, kwargs
, чтобы напечатать то, что было передано функции.
@debug def add_numbers(x, y): return x + y add_numbers(7, y=5,) # Output: Calling add_numbers with args: (7) kwargs: {'y': 5} \n add_numbers returned: 12
3 — Обработчик исключений
exception_handler
оболочка будет перехватывать любые исключения, вызванные функцией divide
, и обрабатывать их соответствующим образом.
Мы можем настроить обработку исключений в функции-оболочке в соответствии с вашими требованиями, например зарегистрировать исключение или выполнить дополнительные действия по обработке ошибок.
def exception_handler(func): def wrapper(*args, **kwargs): try: return func(*args, **kwargs) except Exception as e: # Handle the exception print(f"An exception occurred: {str(e)}") # Optionally, perform additional error handling or logging # Reraise the exception if needed return wrapper
Это становится очень полезным, чтобы навести порядок в нашем коде и установить унифицированную процедуру обработки исключений и регистрации ошибок.
@exception_handler def divide(x, y): result = x / y return result divide(10, 0) # Output: An exception occurred: division by zero
4 — Входной валидатор
Эта функция-оболочка проверяет входные аргументы функции на соответствие заданным условиям или типам данных. Его можно использовать для обеспечения правильности и непротиворечивости входных данных.
Другой способ сделать это — создать бесчисленное количество
assert
строк внутри функции, которую мы хотим использовать для проверки входных данных.
Чтобы добавить проверки к оформлению, нам нужно обернуть функцию декоратора другой функцией, которая принимает одну или несколько функций проверки в качестве аргументов. Эти функции проверки отвечают за проверку того, соответствуют ли входные значения определенным критериям или условиям.
Сама функция validate_input
теперь действует как декоратор. Внутри функции-оболочки аргументы ввод и ключевое слово проверяются на соответствие предоставленным функциям проверки. Если какой-либо аргумент не проходит проверку, он вызывает ValueError
с сообщением, указывающим на недопустимый аргумент.
def validate_input(*validations): def decorator(func): def wrapper(*args, **kwargs): for i, val in enumerate(args): if i < len(validations): if not validations[i](val): raise ValueError(f"Invalid argument: {val}") for key, val in kwargs.items(): if key in validations[len(args):]: if not validations[len(args):][key](val): raise ValueError(f"Invalid argument: {key}={val}") return func(*args, **kwargs) return wrapper return decorator
Чтобы вызвать проверенный ввод, нам нужно определить функции проверки. Например, можно использовать две функции проверки. Первая функция (lambda x: x > 0
) проверяет, больше ли аргумент x
0, а вторая функция (lambda y: isinstance(y, str)
) проверяет, является ли аргумент y
строковым типом.
Важно убедиться, что порядок функций проверки соответствует порядку аргументов, которые они должны проверять.
@validate_input(lambda x: x > 0, lambda y: isinstance(y, str)) def divide_and_print(x, message): print(message) return 1 / x divide_and_print(5, "Hello!") # Output: Hello! 1.0
5 — Повторить попытку
Эта оболочка повторяет выполнение функции заданное количество раз с задержкой между попытками. Это может быть полезно при работе с сетевыми или API-вызовами, которые иногда могут завершаться сбоем из-за временных проблем.
Чтобы реализовать это, мы можем определить другую функцию-оболочку для нашего декоратора, как в нашем предыдущем примере. Однако на этот раз вместо предоставления функций проверки в качестве входных переменных мы можем передавать определенные параметры, такие как max_attemps
и delay
.
Когда вызывается украшенная функция, вызывается функция wrapper
. Он отслеживает количество сделанных попыток (начиная с 0) и входит в цикл while. Цикл пытается выполнить декорированную функцию и в случае успеха немедленно возвращает результат. Однако, если возникает исключение, он увеличивает счетчик попыток и выводит сообщение об ошибке, в котором указывается номер попытки и конкретное возникшее исключение. Затем он ожидает указанную задержку с использованием time.sleep
перед повторной попыткой выполнения функции.
import time def retry(max_attempts, delay=1): def decorator(func): def wrapper(*args, **kwargs): attempts = 0 while attempts < max_attempts: try: return func(*args, **kwargs) except Exception as e: attempts += 1 print(f"Attempt {attempts} failed: {e}") time.sleep(delay) print(f"Function failed after {max_attempts} attempts") return wrapper return decorator
Чтобы вызвать функцию, мы можем указать максимальное количество попыток и продолжительность времени в секундах между каждым вызовом функции.
@retry(max_attempts=3, delay=2) def fetch_data(url): print("Fetching the data..") # raise timeout error to simulate a server not responding.. raise TimeoutError("Server is not responding.") fetch_data("https://example.com/data") # Retries 3 times with a 2-second delay between attempts
Заключение
Оболочки Python — это мощные инструменты, которые могут улучшить ваш опыт программирования на Python. Используя оболочки, вы можете упростить сложные задачи, улучшить читаемость кода и повысить производительность.
В этой статье мы рассмотрели пять примеров оболочек Python:
- Обертка таймера
- Оболочка отладчика
- Оболочка обработчика исключений
- Оболочка валидатора ввода
- Обертка повторной попытки функции
Включение этих оболочек в ваши проекты поможет вам писать более чистый и эффективный код Python и вывести свои навыки программирования на новый уровень.
Понравилась эта история?
Подпишитесь бесплатно, чтобы получать уведомления, когда я публикую новую историю.
Хотите читать более трех бесплатных историй в месяц? — Станьте участником Medium за 5$/месяц. Вы можете поддержать меня, используя мою реферальную ссылку при регистрации. Я получу комиссию без дополнительных затрат для вас.
Если эта статья предоставила вам решение, которое вы искали, вы можете поддержать меня в моем личном аккаунте. Ваша поддержка всегда приветствуется ❤
Дополнительные материалы на PlainEnglish.io.
Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .