zoukankan      html  css  js  c++  java
  • python 高级一点的用法,猴子补丁与元类

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

    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就明白了,用时在查。



     
  • 相关阅读:
    剑指offer--03.从尾到头打印链表
    剑指offer--02.替换空格
    剑指offer--01.二维数组中的查找
    JAVA日记之mybatis-3一对一,一对多,多对多xml与注解配置
    SpringBoot 2.x 自定义拦截器并解决静态资源访问被拦截问题
    springboot项目WEB-INF 目录 jsp页面报404
    Spring Boot 配置拦截器方式
    通过idea创建Maven项目整合Spring+spring mvc+mybatis
    idea创建maven项目
    PLSQL操作Oracle创建用户和表
  • 原文地址:https://www.cnblogs.com/ilovewuzhaoxia/p/7284345.html
Copyright © 2011-2022 走看看