无知的 TonySeek

Yet Another Seeker

杀死 subprocess.Popen 的子子孙孙

Python 标准库 subprocess.Popen 是 shellout 一个外部进程的首选,它在 Linux/Unix 平台下的实现方式是 fork 产生子进程然后 exec 载入外部可执行程序。

于是问题就来了,如果我们需要一个类似“夹具”的子进程(比如运行 Web 集成测试的时候跑起来的那个被测试 Server), 那么就需要在退出上下文的时候清理现场,也就是结束被跑起来的子进程。

最简单粗暴的做法可以是这样:

process_fixture.py
 @contextlib.contextmanager
 def process_fixture(shell_args):
     proc = subprocess.Popen(shell_args)
     try:
         yield
     finally:
         # 无论是否发生异常,现场都是需要清理的
         proc.terminate()
         proc.wait()


 if __name__ == '__main__':
     with ...

Flask 的 Context 机制

用过 Flask 做 Web 开发的同学应该不会不记得 App Context 和 Request Context 这两个名字——这两个 Context 算是 Flask 中比较特色的设计。[1]

从一个 Flask App 读入配置并启动开始,就进入了 App Context,在其中我们可以访问配置文件、打开资源文件、通过路由规则反向构造 URL。[2] 当一个请求进入开始被处理时,就进入了 Request Context,在其中我们可以访问请求携带的信息,比如 HTTP Method、表单域等。[3]

所以,这两个 Context 也成了 Flask 框架复杂度比较集中的地方,对此有评价认为 Flask 的这种设计比 Django、Tornado ...

为 C/C++ 库定制 Python Binding

这应该是个非常常见的需求了吧。可能因为性能原因需要自己编写一部分 C 代码,可能因为需要的第三方库是 C/C++ 编写的。

我遇到这个问题是因为希望将淘宝发的一个切图实现 tclip 放到 Python 上用。和几个同事都尝试折腾了这个问题,总结出了几种可行的方法。

用装饰器注册 Python 函数

注册回调函数应该是开发中很常见的一种行为。这在 Python 中通常通过装饰器来实现,看起来比较漂亮:

flaskr.py
 @app.route("/")
 def home():
     return "It works."

但是这种用法常常带来一种隐藏的“惊讶”,比如说:

记录一些坑

用动态语言编写一些简单的应用时,好的 ORM 往往能带来开发效率的提升 —— 尽管 ORM 为不少大型项目所不齿。Python 社区的 ORM 框架最著名的莫属 SQLAlchemy,它的特点是利用 Python 的元编程支持构造了一套既能照顾到面向对象开发习惯,又能向下支持复杂数据库查询操作的 DSL。这类框架在分类上,应该属于抽象层。

Python 描述符(descriptor) 杂记

Python 引入的“描述符”(descriptor)语法特性真的很黄很暴力,我觉得这算是 Python 对象模型的核心成员之一。Python 语言设计的紧凑很大程度上得益于它。所以写一篇笔记文记录关于描述符我知道的一切。

用 greenlet 协程处理异步事件

自从 PyCon 2011 协程成为热点话题以来,我一直对此有着浓厚的兴趣。为了异步,我们曾使用多线程编程。然而线程在有着 GIL 的 Python 中带来的性能瓶颈和多线程编程的高出错风险,“协程 + 多进程”的组合渐渐被认为是未来发展的方向。技术容易更新,思维转变却需要一个过渡。我之前在异步事件处理方面已经习惯了回调 + 多线程的思维方式,转换到协程还非常的不适应。这几天我非常艰难地查阅了一些资料并思考,得出了一个可能并不可靠的总结。尽管这个总结的可靠性很值得怀疑,但是我还是决定记录下来,因为我觉得既然是学习者,就不应该怕无知。如果读者发现我的看法有偏差并指出来,我将非常感激。

在 Python 中实现 Ruby 的 Open Class 和特异方法

Ruby 中的 OpenClass 是个非常方便的特性,我们可以扩充一个已有的类,往里面添加方法。甚至还能脱离类,向实例中添加该实例独有的方法,称为“特异方法”。这种做法的前提是语言具有足够的动态特性,能够运行时更改语言结构,所谓“ 元编程 ”(Meta-Programming)能力。

Python 也有类似的能力,但是不像 Ruby 有原生的语法支持。在 Python 中实现 OpenClass 和特异方法基本原理与 Ruby 中的原理类似——“函数、方法也是一种对象”。

本文只讨论 Python 的 新式类 ,对于 old-style class 保持无视。

先让简单的命令模式消失吧

最近读《Ruby 设计模式》 [1] (第 n 次重读),对其中的一个观点特别认同:设计模式终将随着语言抽象能力的强化而消失在代码中。正如作者曾经在 C 语言中用函数指针结构体管理操作特定结构体的“面向对象设计模式”,随着面向对象融入语言而消失。GoF 的设计模式很经典,但是在 Ruby、Python 等表达力强大的语言火热之后,部分原来可以称之为“模式”的做法已经开始有了融入语言的趋势。

虽然这篇博客讨论的是命令模式,但我不会再絮叨一边命令模式是什么,已经有非常详细的资料 [2] 在先了。我想讨论的是关于在相对传统高级语言更“高级”的语言中,命令模式更佳的实现方式。这类语言包括但不限于:Python、Ruby、Scala、JavaScript。

Python 中 print 语句的诡异用法

真是孤陋寡闻了,到了今日看了一篇博客 [1] 才知道 Python 中 print 语句有种类似 C++ 流操作符的诡异用法:

import sys

error_log = open("./error.log", "a")
print >> sys.stderr, "some error message"
print >> error_log, "some error message"

error_log.close()

当然了,只有 2.x 的 Python 才有 print 语句一说,在 Python 3.x 中(以及导入了 from __future__ import print_function 的 ...