python 杂谈(1)

既然 style guide 上已经列举出来了很多有意思东西,这里就开始这个系列了

metaclass

我们可以先看看 python 提供的 abc,它是一个基于 metaclass 概念实现的 module,我们只需要在定义一个 class 的时候指定 __metaclass__ 为 abc.ABCMeta 就可以直接使用这个 module 提供的一些功能,比如 @abstractmethod,registration 等。为了理解这个 module 我们就必须理解 python 的 metaclass 到底是一个什么样的机制。从某种意义上来说 python 这一点应该是向 ruby 学习的。这部分参看这里

python 的核心思想就是万物皆对象,我们所有的对象都存在一个生成它的“类”,而类本身也是一个对象,每当我们在一个 module 里面写 class 的时候可以理解为我们定义了一个“类对象”,这些类对象的共同特点就是提供 __init__ 方法,类似与一个 factory method 用于生成我们看到的对象。但是类与一般对象的区别在于,一个对象生成了之后可以 dynamically change,而类按照写法是 statically code 在 module 里面的,我们在某些时候希望能够通过程序改变类对象本身,这就涉及到了 metaclass。

metaclass 与 type 关键字紧密相关,type 不仅可以取得对象的类别,还可以通过类名、一个 tuple (父类列表)和一个 dict (成员)生成一个类,也就是说它可以构造类对象。Python 默认使用 type 来生成类对象,同时允许我们提供一个类似 type 的东西,来改变 type 默认的行为。为了证实这一点,我们可以通过 __class__ 来看,一般的对象 __class__ 指向对应的类对象,而对应的类对象的 __class__ 则为 type。

从某种意义上来说 metaclass 可以认为是类对象的 factory method,只是它可以走得更远。python 允许我们通过 __metaclass__ 来覆盖默认的 type 作为一个类的 metaclass

  • 我们可以用任意一个函数作为 metaclass,只要它和 type 一样接受类名(字符串),一个 tuple(父类列表)和一个 dict(成员列表)并且返回一个类对象就行,怎么生成类对象呢?我们还是可以将对应的参数 forward 给 type 的
  • 也可以用一个类,只要它继承 type,提供了 __new__ 方法,这个方法和 type 接受的参数类似,但是多一个参数表示其上级 metaclass

很显然,有了这个认识我们就可以想象当我们改变一个类的 metaclass 之后,其子类的构造将会调用一样的 code,这时诸如 abc 之类的小把戏就可以通过一个查询来实现对应的继承,检查 abstract 方法什么的了。希望了解更多的话,阅读这个 PEP 吧。

copy

Python 虽说是 GC 语言,但是它使用了比较保守的 copy 语义,很多时候只是传递引用,这会导致一些看起来没什么问题的代码出现意想不到的情况,比如

a = [list()] * 5
a[0].append(1)
print a

结果居然是 [[1], [1], [1], [1], [1]]。我们可以如下解决

a = [list() for _ in xrange(5)]

这种问题在 numpy 和 pandas 里面也经常出现,记得需要的时候显式的注明 deep=True 或者用 copy.deepcopy。

annotation

annotation 本身就是一个函数,它输入是被 annotate 的对象(类,函数),输出也是同类的对象。annotation 如果还有参数,其本质就是一个返回前者的函数,所以有点 nestedness。更多参看这里

python 也支持 annotation class,一般需要保持额外的 state 的时候 class 的 __init__ 就可以发挥作用,其 __call__ 方法和 function 是一样的,def 本身也就是定义一个函数对象,它带有 __call__ 的实现。

inspect

这个 module 允许我们做一些类似 reflection 的事情,比如看看某些对象是不是函数或者别的什么,这在很多 annotation 的实现里面非常有用,annotation 本身是一个函数,输入是一个类(或者函数),输出是一个被其处理过的类(或者函数),这时候我们可能需要通过这个对象的 __name__ 做一些查询等操作,那就是字符串转换到某些条件,这时看看 inspect 是个不错的选择。

__getattr__

这是一个 fallback 的查询方法,当 self 里面不存在 也没有通过 def 定义对应的成员时就会调用 __getattr__ 方法,默认它抛出异常,我们可以在这里加一些自己的逻辑,比如通过网络查询等等。

——————
And it came to pass, as he interpreted to us, so it was; me he restored unto mine office, and him he hanged

Advertisements
python 杂谈(1)

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s