学习过程中总会遇到一些从字面上看起来很复杂,而事实上很简单的知识,Python中的鸭子类型和Monkey Patch就是这样的知识。
鸭子类型
什么是鸭子类型?
“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
鸭子类型是编程语言中动态类型语言中的一种设计风格,一个对象的特征不是由父类决定,而是通过对象的方法决定的。
静态语言中对象的特性取决于其父类。而动态语言则不一样,比如迭代器,任何实现了 **iter** 和 **next**方法的对象都可称之为迭代器,但对象本身是什么类型不受限制,可以自定义为任何类。
简而言之:
一个函数F期望接收类A的实例化对象,在Python中给F传入对象时,我们传入的对象可以不是类A的实例化,只要传入入一个与类A有相同的方法接口的类的实例化对象就行(不一定所有接口相同,需要用到的方法相同就行);如果在Java/C++中就必须传入类A或者类A的子类的实例化对象!
鸭子类型通常得益于”不”测试方法和函数中参数的类型,而是依赖文档、清晰的代码和测试来确保正确使用,这既是优点也是缺点,缺点是需要通过文档才能知道参数类型,为了弥补这方面的不足,Python3.6引入了类型信息,定义变量的时候可以指定类型,例如:
Monkey Patch
所谓猴子补丁就是在程序运行的过程中动态的修改一些模块、类、方法,而不是在静态代码中去修改相应的实现。
简单示例:不修改time模块的静态代码,在运行时用自定义的函数替换time模块time函数
借用网上一个更加通俗一点的例子:
小明最喜欢吃苹果,上帝想让小明最喜欢吃的东西变为香蕉。但是小明已经出生了,上帝不可能把小明送回娘胎修改小明最喜欢吃的东西,只能去改变出生后的小明,于是上帝对小明使用了monkey patch,翻译成代码语言就是下面的代码:
1 | class XiaoMing(object): |
monkey patch的应用:
gevent库通过monkey patch修改Python自带的一些标准库,
gevent的monkey可以为socket、dns、time、select、thread、os、ssl、httplib、subprocess、sys、aggressive、Event、builtins、signal模块打上的补丁,打上补丁后他们就是非阻塞的了。
如:gevent.monkey.patch_select(),gevent.monkey.patch_socket()就可以将select和socket变为非阻塞。