Декоратор это одна из моих любимых функций Python. Несмотря на то, что, по -видимому, смущены сначала, это просто функция, которая принимает другую функцию в качестве параметра и возвращает другую функцию.
декоратор: фанк -> фанк
Это возможно, потому что в Python функция
является первоклассным гражданином, что означает, что функция может использоваться в качестве параметра, возвращаемого значения и может быть назначена переменной.
Однажды понято, декоратор
может использоваться в различных ситуациях, и некоторые из которых будут обсуждаться ниже.
По определению,
Декоратор – это функция, которая выполняет другую функцию и расширяет поведение последней функции без явного модификации ее
Конкретно приведенный ниже код:
@decorator def f(argument): ...
заменит f
по Декоратор (F)
: звонок f (аргумент)
тогда эквивалентно Декоратор (f) (аргумент)
Анкет
Flask, популярная и легкая веб -структура широко использует декоратор, который приводит к элегантному и интуитивному коду. Использование Decorator можно найти по всей структуре, от определения маршрутов до добавления крючков к жизненному циклу приложения/запроса.
В этом небольшом посте будут обсуждаться некоторые варианты использования декораторов в колбе. Обратите внимание, что этот пост предназначен для пользователей, у которых уже есть опыт работы с колбами и декораторами. Примерами кода также являются в основном псевдокод, чтобы проиллюстрировать идеи, а не сразу можно использовать. Если вы хотите узнать о колбе или декораторе, вы можете найти некоторые ресурсы в конце поста.
Во -первых, как реализовано @app.route?
Первый пример колбы обычно начинается с чего -то вроде:
@app.route("/") def index(): return "Hello world"
Имея app.route
как декоратор, функция Индекс
зарегистрирован для маршрута /
так что когда этот маршрут запрашивается, Индекс
вызывается, и его результат «Hello World» возвращается клиенту (будь то веб -браузер, curl и т. Д.).
Вы когда -нибудь задумывались, как повсеместно @app.route
реализуется? Поскольку декоратор обычно используется для изменения поведения функции, его эффект обычно можно увидеть при вызываемой этой функции. Тогда как Индекс
нигде не называется нигде в коде.
Непопулярным фактом о декораторе является то, что он время определения, а не время выполнения , это Индекс
будет заменен на app.route ('/') (index)
Когда модуль импортирован Анкет Тот факт, что этот регистр осуществляется во время определения, здесь важен, как если бы это было не так, Флеска не сможет узнать о наличии индекса.
Логика реализации @app.route
на самом деле довольно просто, в основном Индекс
добавляется в глобальную переменную отображения URL-функции, которая будет выполнена на поиске при появлении запроса:
class App: route_functions = {} def route(url_pattern): def wrap(f): route_functions[url_pattern] = f return f return wrap
Поэтому при замене Индекс
по app.route ("/") (index)
, Индекс
добавляется в route_functions
это содержит совместимость с функцией маршрута.
Вход в систему декоратор
Допустим, у вас есть приложение Flask, которое позволяет пользователю добавлять твиты. Каждый твит принадлежит пользователю, и только зарегистрированный пользователь может добавить твит. Поэтому вы хотите ограничить некоторые маршруты только для регистрации пользователей, и если пользователь не вошел в систему, он будет перенаправлен на страницу входа в систему.
Добавление проверки входа для каждого маршрута довольно громоздко и нарушает СУХОЙ принцип. Было бы очень удобно, если бы мы могли просто украсить такие маршруты с помощью @Login_Required, и все проверки входа будут выполнены автоматически.
@app.route("/add_tweet") @login_required def add_tweet(): ...
Предположим, что проверка пользователя использует cookie, Login_Required
Сначала проверяет файл cookie, если файл cookie не действителен, перенаправить пользователя на страницу входа в систему. В противном случае позвоните add_tweet
:
from functools import wraps def login_required(f): @wraps(f) def wrap(*args, **kwargs): # if user is not logged in, redirect to login page if not request.headers["authorization"]: return redirect("login page") # get user via some ORM system user = User.get(request.headers["authorization"]) # make user available down the pipeline via flask.g g.user = user # finally call f. f() now haves access to g.user return f(*args, **kwargs) return wrap
Обратите внимание, что Login_Required
нужно размещать после app.route
так login_required (add_tweet)
будет называться, а не только add_tweet
Когда маршрут соответствует. В противном случае, если Login_Required
помещается до app.route
, только add_tweet
вызывается, когда маршрут запрашивается, и поэтому проверка требований входа не имеет никакого эффекта.
Роли на основе декоратор
Предыдущий декоратор входа может быть расширен, чтобы учитывать различные роли пользователя. Допустим, у нас есть пользователи администратора, которые могут вызывать маршруты, которые не могут другие пользователи. Было бы неплохо иметь декоратор admin_login_required
, что при использовании с Login_Required
Знает маршрут, доступный только для пользователей администратора.
def admin_login_required(): def wrap(*args, **kwargs): # user is available from @login_required if not g.user.is_admin: return "you need to be admin", 401 return f(*args, **kwargs)
Поэтому, чтобы украсить маршрут, который требует доступа к администратору, можно просто добавить эти 2 декоратора:
@app.route("/admin/delete_user") @login_required @admin_login_required def admin_delete_user(): ...
Заказ здесь снова важен: admin_login_required
Должен быть размещен после Login_Required
Чтобы получить выгоду от g.user
установить Login_Required
Анкет
Другое использование
Использование декоратора может элегантно решить различные сухие проблемы:
- Получите ввод из запроса запроса, JSON, форма с проверкой типов, чтобы, если ввод отсутствует или неправильно, верните 400
- Добавьте изготовленное время, чтобы узнать, какие маршруты медленно
- Кэширование страницы на основе параметров URL
- И т.д
Некоторые отличные ресурсы ИМО для изучения колбы и декораторов:
https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world
http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/
https://www.thecodeship.com/patterns/guide-to-python-function-decorators/
Оригинал: “https://dev.to/sonnk/python-decorator-and-flask-4c16”