Начало работы с Flask, самой популярной упрощенной платформой Python на Github

задняя часть Python открытый источник Flask

Недавно Flask наконец выпустил обновление версии 1.0, и прошло 8 лет с тех пор, как проект был открыт для последней версии 1.0 flask.

# app.py
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()

бегатьpython app.py, откройте браузер для доступаhttp://localhost:5000/Вы можете увидеть вывод страницыHello World!

Flask появился на свет в День дурака в 2010. Изначально это была просто маленькая игрушка, написанная автором нечаянно, но неожиданно ставшая популярной потихоньку. Долгих 8 лет flask не выпускал серьезной официальной версии, но это не может помешать ему стать самым расхваливаемым веб-фреймворком Python на github.

Два наиболее важных компонента встроены в ядро ​​flask, а все остальные компоненты интегрированы с помощью легко расширяемой системы плагинов. Два встроенных компонента — это werkzeug и jinja2.

werkzeug — это набор инструментов для написания программ Python WSGI.Его структурный дизайн и качество кода широко хвалят в сообществе открытого исходного кода, а его исходный код считается одной из самых достойных библиотек с открытым исходным кодом в области технологии Python.

# wsgi.py
from werkzeug.wrappers import Request, Response

@Request.application
def application(request):
    return Response('Hello World!')

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    run_simple('localhost', 4000, application)

бегатьpython wsgi.pyОткрытый доступ в браузереhttp://localhost:4000/Вы можете увидеть вывод страницыHello World!

Вы смотрели на werkzeug.routing?Трудно найти что-то более простое, более автономное или более чистое WSGI, чем Werkzeug, в общем-то я большой его поклонник!

Алекс Мартелли, автор Python in a Nutshell && Python Cookbook

jinja2 — чрезвычайно мощная система шаблонов, она отлично поддерживает китайский язык unicode, каждый шаблон работает в безопасной среде песочницы, а код шаблона, написанный на jinja2, очень красив.

{% extends "layout.html" %}
{% block body %}
  <ul>
  {% for user in users %}
    <li><a href="{{ user.url }}">{{ user.username }}</a></li>
  {% endfor %}
  </ul>
{% endblock %}

Общим для двух библиотек, werkzeug и jinja2, является то, что написанный код приятен для глаз, авторArmin RonacherВыбор этих двух библиотек в качестве краеугольных камней flask показывает, что у автора очень разборчивый вкус кода. Так кто же автор, clang! Он красивый парень из Австралии!

Что ж, посплетничаем и приступаем к делу, начнем испытывать на себе волшебное очарование фляжки.

установить колбу

pip install flask

API расчета Пи

Пи можно получить, используя сумму квадратов, обратных положительным целым числам, и по мере того, как этот ряд стремится к бесконечности, значение будет все ближе и ближе к Пи.

# flask_pi.py
import math

from flask import Flask, request

app = Flask(__name__)

@app.route("/pi")
def pi():
    # 默认参数
    n = int(request.args.get('n', '100'))
    s = 0.0
    for i in range(1, n):
        s += 1.0/i/i
    return str(math.sqrt(6*s))

if __name__ == '__main__':
    app.run()

бегатьpython flask_pi.py, откройте браузер для доступаhttp://localhost:5000/pi?n=1000000, вы можете увидеть вывод страницы3.14159169866, это значение очень близко к пи.

Уведомлениеpi()Возвращаемое значение не может быть числом с плавающей запятой, поэтому вы должны использоватьstrпреобразовать в строку

Присмотревшись к коду, вы также заметите специальную переменнуюrequest, которая выглядит как глобальная переменная. Очень странно получать текущие параметры запроса из глобальных переменных. Если в многопоточной среде, как гарантировать, что каждый поток получает параметры запроса, которые обрабатывает текущий поток? Таким образом, это не может быть глобальная переменная, это локальная переменная потока.Локальная переменная потока ничем не отличается от глобальной переменной по внешнему виду, но при доступе к локальной переменной потока каждый поток получает объект, разделяемый внутри текущего потока.

Результаты расчета кеша

Во избежание двойного счета будемpi(n)Значение кэшируется и может быть запрошено напрямую в следующий раз. В то же время мы больше не возвращаем простую строку, мы возвращаем строку json, в которой есть кэшированное поле, чтобы определить, получен ли текущий результат непосредственно из кеша.

import math
import threading

from flask import Flask, request
from flask.json import jsonify

app = Flask(__name__)


class PiCache(object):

    def __init__(self):
        self.pis = {}
        self.lock = threading.RLock()

    def set(self, n, pi):
        with self.lock:
            self.pis[n] = pi

    def get(self, n):
        with self.lock:
            return self.pis.get(n)


cache = PiCache()


@app.route("/pi")
def pi():
    n = int(request.args.get('n', '100'))
    result = cache.get(n)
    if result:
        return jsonify({"cached": True, "result": result})
    s = 0.0
    for i in range(1, n):
        s += 1.0/i/i
    result = math.sqrt(6*s)
    cache.set(n, result)
    return jsonify({"cached": False, "result": result})

if __name__ == '__main__':
    app.run()

бегатьpython flask_pi.py, откройте браузер для доступаhttp://localhost:5000/pi?n=1000000, вы можете увидеть вывод страницы

{
  "cached": false,
  "result": 3.141591698659554
}

Обновите страницу еще раз, мы можем заметить, что поле cached стало истинным, что указывает на то, что результат действительно был закеширован.

{
  "cached": true,
  "result": 3.141591698659554
}

Читатели могут спросить, зачем кеш-классу PiCache нужно использовать RLock? Это связано с тем, что чтение и запись словаря Python не являются полностью потокобезопасными в многопоточной среде, и для защиты структуры данных необходимо использовать блокировку.

Распределенный кеш

Вышеуказанный кэш - это только кэш памяти. После перезапуска процесса кэшированные результаты исчезают, а следующий расчет должен быть перезапущен.

if __name__ == '__main__':
    app.run('127.0.0.1', 5001)

Если второй порт 5001 открыт для предоставления услуг, второй процесс не может пользоваться кешем памяти первого процесса и должен быть пересчитан. Поэтому здесь представлен распределенный кеш Redis, чтобы совместно использовать кеш вычислений, избегать повторных вычислений между процессами, а также избегать перезапуска и пересчета.

import math
import redis

from flask import Flask, request
from flask.json import jsonify

app = Flask(__name__)


class PiCache(object):

    def __init__(self, client):
        self.client = client

    def set(self, n, result):
        self.client.hset("pis", str(n), str(result))

    def get(self, n):
        result = self.client.hget("pis", str(n))
        if not result:
            return
        return float(result)


client = redis.StrictRedis()
cache = PiCache(client)


@app.route("/pi")
def pi():
    n = int(request.args.get('n', '100'))
    result = cache.get(n)
    if result:
        return jsonify({"cached": True, "result": result})
    s = 0.0
    for i in range(1, n):
        s += 1.0/i/i
    result = math.sqrt(6*s)
    cache.set(n, result)
    return jsonify({"cached": False, "result": result})

if __name__ == '__main__':
    app.run('127.0.0.1', 5000)

бегатьpython flask_pi.py, откройте браузер для доступаhttp://localhost:5000/pi?n=1000000, вы можете увидеть вывод страницы

{
  "cached": false,
  "result": 3.141591698659554
}

Обновите страницу еще раз, мы можем заметить, что поле cached стало истинным, что указывает на то, что результат действительно был закеширован.

{
  "cached": true,
  "result": 3.141591698659554
}

Перезапустите процесс и снова обновите страницу.Кэшированные выходные данные поля со страницы чтения по-прежнему истинны, что указывает на то, что кэшированные результаты больше не теряются из-за перезапуска процесса.

MethodView

Написал Django, друзья могут спросить, поддержка Flask в виде классового API написана так, ответ да. Здесь мы используем встроенную поддержку Flask MethodView для переделки вышеуказанных сервисов.

import math
import redis

from flask import Flask, request
from flask.json import jsonify
from flask.views import MethodView

app = Flask(__name__)


class PiCache(object):

    def __init__(self, client):
        self.client = client

    def set(self, n, result):
        self.client.hset("pis", str(n), str(result))

    def get(self, n):
        result = self.client.hget("pis", str(n))
        if not result:
            return
        return float(result)


client = redis.StrictRedis()
cache = PiCache(client)


class PiAPI(MethodView):

    def __init__(self, cache):
        self.cache = cache

    def get(self, n):
        result = self.cache.get(n)
        if result:
            return jsonify({"cached": True, "result": result})
        s = 0.0
        for i in range(1, n):
            s += 1.0/i/i
        result = math.sqrt(6*s)
        self.cache.set(n, result)
        return jsonify({"cached": False, "result": result})


# as_view提供了参数可以直接注入到MethodView的构造器中
# 我们不再使用request.args,而是将参数直接放进URL里面,这就是RESTFUL风格的URL
app.add_url_rule('/pi/<int:n>', view_func=PiAPI.as_view('pi', cache))


if __name__ == '__main__':
    app.run('127.0.0.1', 5000)

Мы достигли методы Get Methods, указывающие, что API поддерживает только метод получения HTTP-запроса. Если вы хотите поддержать пост, поставить и удалять методы, требуют, чтобы пользователь перейти к реализации этих методов.

MethodView по умолчанию в Flask работает хорошо, но этого недостаточно, он не может предоставлять несколько API-сервисов с разными URL-именами в одном классе. Итак, далее мы представляем расширение фляги flask-classy, ​​чтобы решить эту проблему.

Небольшая тестовая колба-удлинитель классная

Первым шагом в использовании расширения является установка расширенияpip install flask-classy, а затем мы добавляем новый сервис API в тот же класс для вычисления рядов Фибоначчи.

import math
import redis

from flask import Flask
from flask.json import jsonify
from flask_classy import FlaskView, route  # 扩展

app = Flask(__name__)

# pi的cache和fib的cache要分开
class PiCache(object):

    def __init__(self, client):
        self.client = client

    def set_fib(self, n, result):
        self.client.hset("fibs", str(n), str(result))

    def get_fib(self, n):
        result = self.client.hget("fibs", str(n))
        if not result:
            return
        return int(result)

    def set_pi(self, n, result):
        self.client.hset("pis", str(n), str(result))

    def get_pi(self, n):
        result = self.client.hget("pis", str(n))
        if not result:
            return
        return float(result)


client = redis.StrictRedis()
cache = PiCache(client)


class MathAPI(FlaskView):

    @route("/pi/<int:n>")
    def pi(self, n):
        result = cache.get_pi(n)
        if result:
            return jsonify({"cached": True, "result": result})
        s = 0.0
        for i in range(1, n):
            s += 1.0/i/i
        result = math.sqrt(6*s)
        cache.set_pi(n, result)
        return jsonify({"cached": False, "result": result})

    @route("/fib/<int:n>")
    def fib(self, n):
        result, cached = self.get_fib(n)
        return jsonify({"cached": cached, "result": result})

    def get_fib(self, n): # 递归,n不能过大,否则会堆栈过深溢出stackoverflow
        if n == 0:
            return 0, True
        if n == 1:
            return 1, True
        result = cache.get_fib(n)
        if result:
            return result, True
        result = self.get_fib(n-1)[0] + self.get_fib(n-2)[0]
        cache.set_fib(n, result)
        return result, False


MathAPI.register(app, route_base='/')  # 注册到app


if __name__ == '__main__':
    app.run('127.0.0.1', 5000)

доступhttp://localhost:5000/fib/100, мы можем увидеть вывод страницы

{
  "cached": false,
  "result": 354224848179261915075
}

доступhttp://localhost:5000/pi/10000000, количество вычислений относительно велико, поэтому еще один поворот, вывод окончательной страницы

{
  "cached": false,
  "result": 3.141592558095893
}

Читайте более продвинутые статьи, обратите внимание на номер подписки WeChat »дворовая дыра"

Расширенное чтение

Ляо Сюэфэн учит правильному использованию ThreadLocal

Python Словари в потоке

Здравствуйте, колбу знают почти столбец