无知的 tonyseek

Yet Another Seeker

在 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 的 ...

总结 XSS 与 CSRF 两种跨站攻击

在那个年代,大家一般用拼接字符串的方式来构造动态 SQL 语句创建应用,于是 SQL 注入成了很流行的攻击方式。在这个年代, 参数化查询 [1] 已经成了普遍用法,我们已经离 SQL 注入很远了。但是,历史同样悠久的 XSS 和 CSRF 却没有远离我们。由于之前已经对 XSS 很熟悉了,所以我对用户输入的数据一直非常小心。如果输入的时候没有经过 Tidy 之类的过滤,我一定会在模板输出时候全部转义。所以个人感觉,要避免 XSS 也是很容易的,重点是要“小心”。但最近又听说了另一种跨站攻击 CSRF ,于是找了些资料了解了一下,并与 XSS 放在一起做个比较。

我对策略模式的理解

策略模式(Strategy Pattern)来自四人帮的《设计模式:可复用面向对象软件的基础》一书。先看维基百科的描述:

  • 维基中文站的词条“策略模式” [1]
  • WIKIPEDIA(EN) Strategy Pattern [2]

而我对它的理解,是“隔离出**有多种选择的部分**”,就如工具箱里的多用螺丝刀——一把螺丝刀可以装上十字头、一字头甚至是锥子头。

多用螺丝刀图片,来自维基共享资源,采用知识共享署名-相同方式共享 3.0 Unported 许可协议授权

Python 对象的实例化过程

我们知道,Python 的构造函数有两个,一个是我们最常用的 __init__ ,另一个是很少用到的 __new__ 。而从它们的函数定义 def __new__(cls, [...])def __init__(self, [...]) 可以知道, __init__ 被调用时实例已经被创建(就是 self 参数所引用的);而 __new__ 被调用的时候,实例不一定已被创建(暂时只能这么说),而 __new__ 的第一个参数为当前类的引用。

所以我们可以通过一些途径,跟踪 Python 对象的实例化过程,来研究 __new____init__ 的工作。这个途径就是上一篇博文 利用 with 语法实现可拆卸的装饰器 中用到的函数调用轨迹装饰器。

对象-关系映射的外键映射问题

最近读 Martin Folwer 的《企业应用架构模式》,其中对于关系型数据库与对象模型的同步问题,提到了使用 DataMapper 和工作单元来协调。

而关系型数据库的数据储存和对象模型的差异在于,关系型数据库是不允许集合类型存在的。在典型的 1 - N 关系模式中,是由 N 来保存对 1 的引用(数据库中体现为外键);而在对象模型中, 1 - N 的聚集关系是由 1 来保存 N 的集合。也就是说,数据映射层的一个职责,是完成这个“翻转”过程。

【碎片】PHP 虚代理实现延迟加载

话说这货是从 Martin 大神的《企业应用架构模式》中学到的,辅助 PHP 动态语言的特性,可以比 Java 轻松很多的实现延迟加载——通过一个虚代理占位符。唯一的缺陷,是只能代理对象,不能代理内置基本类型。

我试水的 PHP 领域模型设计中,也是用这个来实现 DomainObject 的延迟加载。

【碎片】tornado 用上装饰器路由

貌似很多人是零配置控啊,喜欢类似 Flask 一类的零配置路由,不需要在 run.py 中写一个长列表,只需要在接受请求的函数 or 类前面加一个装饰器,正如:

from bottle import route, run

@route('/:name')
def index(name='World'):
    return '<strong>Hello %s!</strong>' % name

run(host='localhost', port=8080)

对比 web.py 的集中配置:

import web

urls = ("/.*", "hello")
app = web.application(urls, globals())

class hello:
    def GET(self):
        return 'Hello, world!'

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

貌似二者没神马区别嘛,只不过把集中的配置分散了。当然对于这个问题也是很多不同看法,有人觉得分散了配置不利统一管理,有人觉得把 url 和请求处理者放在一起有利于模块的无缝装卸。当然最理想的是两种选择都存在。在豆瓣上已经看到有人提出 给 web.py 添加装饰器路由的方式 <http://www.douban.com/group/topic/12998784/> _ 了,我自己也写了个 tornado 版的。