码迷,mamicode.com
首页 > 编程语言 > 详细

python 高级一点的用法,猴子补丁与元类

时间:2017-08-04 12:42:42      阅读:896      评论:0      收藏:0      [点我收藏+]

标签:metaclass   关系   nbsp   int   ase   前端   orm   plain   界面   

好久没更新了,今天想想哪些要记录下的,装饰器什么的就不说了,很熟悉了,记录下。

1.monkey patch.

其实就是动态修改类,包括属性方法等的一种方式。

比如a = A() a.foo = foo之类的,但是怎么在运行前修改呢,类似gevent那样用自己的socket替换,

gevent 源码是这样的

from eventlet.green import socket

patcher.inject(‘ftplib‘, globals(), (‘socket‘, socket))

然后inject里sys.modules[‘__patched_module_‘ + module_name] = module这个关键的语句。
也就是说如果要实现这样统一入口的地方patch,就要明白python 寻找变量的方式,LEGB也就是说当python在载入模块的时候,sys.modules里会载入,然后按照LEGB的原则添加到当前模块
这里举一个实际的例子,如果有一天产品需要在所有搜索界面实现一个公用功能,比如记住当前页活着搜索结果,跳转回来也会有,页面涉及几十个甚至上百个,怎么办呢,当然一饿一个改也灭有问题,
但是这样改工作量大,并且容易出错,测试覆盖点多,周期会很长,所以就可以这样里,看下面
def _wraper(fn):
def _render(*args, **kwagrs):
request = args[0]
http_content = args[2]
page = request.GET.get(‘dt_page‘, 0)
try:
page = int(page)
except:
page = 0
http_content.update({‘dt_page‘: page})
return fn(*args, **kwagrs)
return _render
__import__("django.shortcuts")
sys = __import__("sys")
_render_module = sys.modules[‘django.shortcuts‘]
_render_module.render = _wraper(_render_module.render)
因为每个页面都要通过页面渲染,所以直接载入
django.shortcuts并且修改它的render方法变成自己装饰里的render,当然我只是增加了一个dt_page参数而已,在前端点击时候传入参数,当然前端也差不多,就是在js以及页面加载完成后,
用dom.find选择器的方式然后修改里所有链接并加上dt_page参数就实现效果啦,哈哈是不是很神奇。这就是monkeypatch啦,gevent也是这样来替换系统的socket库的。
下面介绍另一种动态修改类的方式。
2.元类
这个比较复杂,我也只是了解,实际当中并咩用到,其实django的ORM就是用元类来实现的。
其实要理解这个,直接就看太抽象了。下面分开说。
1)先有鸡还是先有蛋,object与type
  • object类是所有新式类的父类。

  • type是所有类的类

当然object 本身与type之间关系可能比较模糊:

>>> object.__class__
<type ‘type‘>
>>> object.__bases__ # object 无父类,因为它是链条顶端。
()
- type是一种object, type is kind of object。即Type是object的子类。

>>> type.__bases__
(<type ‘object‘>,)
>>> type.__class__ # type的类型是自己
<type ‘type‘>

所以在Python的世界中,object是父子关系的顶端,所有的数据类型的父类都是它;type是类型实例关系的顶端,所有对象都是它的实例的。

也就是说类本身是实例,它是依靠type生成类实力,与其它编译型语言java,C#不一样,因为它们只有object却没有type类,所以它们不能实现动态修改类。

当然经典类的元类就是继承type的类classobj来生成的,而新式类(继承object)就是由type生成的(如果不手动指定元类的话)。有了这个,想必大家都知道为啥能用元类修改类类吧。好,下面来试试,自定义元类。

 2)首先有一种很简单的方式生成一个类,直接用type,

Foo = type(‘Foo‘, (), {}) 这样就能直接生成一个FOO类。其实就是相当于用type生成了一个FOO类,跟class FOO一个意思,但是平常不这么用。我们怎么动态修改呢?用

关键字__metaclass__就能指定用哪一个类去创建当前类,

class MyMetaClass(type):

  def __new__(cls, name, bases, dct):

 

class MyClass(object):

       __metaclass__ = MyMetaClass

  pass

这样创建的MyClass就是由MyMetaClass来创建的,在MyMetaClass里就可以修改你想创建的类了,这样理解起来是不是不那么抽象了,里面的参数查查API就明白了,用时在查。

 

 



 

python 高级一点的用法,猴子补丁与元类

标签:metaclass   关系   nbsp   int   ase   前端   orm   plain   界面   

原文地址:http://www.cnblogs.com/ilovewuzhaoxia/p/7284345.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!