我们把用 C/C++ 实现的 Python 函数统称为 PyCFunction
。
上一章 mymath
模块的 sum
函数能接受两个 int 参数并对它们求和。然而靠这样的功能还不能写出真正可用的 Python Module。
在本章我们将实现一个更复杂的PyCFunction
以掌握更多必要的细节。
C 拓展 Python 实战(一)——全局观
在本章我们会用 C 实现一个简单的的 Python 内置模块, 以了解用 C/C++ 拓展 Python 时的核心的组件和基本流程。
假设这个模块叫 mymath
, 其中有一个sum
函数:
1 | import mymath |
使用Python标准库上传文件
废话不多说啦, 三个点:
Header
里面设置Content-Type
;Header
里面设置Content-Length
;- 把文件内容读出来, 按格式要求写到 Body 里面.
Python 的赋值和作用域
Tornado 实现 decorator 路由
我也实现了一个 Flask decorator 风格的 Tornado 路由,实现的方式极大地参考了 Flask 的过程(add_url_rule 和 Blueprint)。
Tornado 在新建 Application 的时候, 需要传入一个 handlers 参数, 原本这个 handlers 需要自己手动构建: 收集各个 RequestHandler,给他们分配路径,组成一个 handlers tuple。 这样维护起来非常麻烦。
我实现的功能是:
- 通过 decorator 给每个 RequestHander 即时分配 url pattern;
- 支持根据 API 版本和 Resource 类型自动给 url pattern 添加前缀;
- 可以通过 RequestHander 的类名反向查出 url。
功能一点都不复杂, 实现起来也简单, 不到 100 行代码。下面是我的实现过程。
读 Flask:Blueprint 的大致实现
Flask 的 Blueprint 本质上是一个记录了一系列动作的类, 当 flask app 执行 app.register_blueprint
的时候把这些动作一股脑的全部倒入到 app 这个容器中去.
其大致的执行顺序是:
app = Flask(__name__)
bp = Blueprint('blueprint', __name__)
bp.before_request' \ 'bp.route' \ 'bp.errorhandler
app.register_blueprint
读 Python: functools.wraps 做了什么
Python 标准库 functools 里面的 wraps
装饰器经常用于写装饰器,之前只知道它可以用来保留被装饰函数的元数据,但具体实现的方式和究竟保留了哪些数据都不清楚。最近看 Flask 源码时读到一行代码 return self.record(update_wrapper(wrapper, func))
。 稍微看了一下原来 @wraps(func)
其实就是调用了 update_wrapper
这个函数,于是索性看个明白。
Flask-Admin 快速实现用户权限限制
这个办法基于以下两个事实:
- Flask Admin 本身是一个 Flask 蓝图
- Flask 的 ModelView 类可以通过
can_delete = True/False
等来关闭/开启相应的操作
所以实现的办法是,给 Flask-Admin 蓝图的before_request_funcs
注册一个check_user_permission
函数,在每次请求之前根据用户的权限来刷新 ModelView 的设置。
而蓝图的before_request
必须要在app.register_blueprint
调用之前,根据 Flask-Admin 创建蓝图和注册蓝图的流程来看,复写 ModelView 的create_blueprint
这个函数就可以了。
读Flask: 一次完整的Request和Response周期
Flask只是一个python web框架,框架和server之间的数据交流,都是基于PEP3333所规范的WSGI, server调用framwork的某个callable进行数据交流。 这个callable, 可以是定义了__call__
方法的类,或者任何函数等。
而Flask应用的数据入口和出口(callable)就是Flask类实例的wsgi_app
函数。
1 | def wsgi_app(self, environ, start_response): |
wsgi_app
接受从server发过来的environ
环境变量,并且根据这个变量创建一个request context,然后在这个context下进行数据处理,最后返回数据到server。