zoukankan      html  css  js  c++  java
  • Python 元类

      1 Python 元类 - Metaclasses
      2 
      3 默认情况下儿, classes 是有 type() 构造的.
      4 类的结构体在一个新的 namespace 被执行, 类的名字 class name 绑定(bound locally)到 
      5 type(name, bases, namespace) 的结果上.
      6 然而, 类的构造过程可以用户定义 - 在定义类的时候通过传入一个 metaclass 关键字;
      7 或者通过继承至一个有 metaclass 关键字的父类.
      8     如,
      9             class Meta(type):
     10                  pass
     11     
     12             class MyClass(metaclass=Meta):
     13                 pass
     14         or
     15             class MySubclass(MyClass):
     16                 pass
     17     
     18class 定义中的其他关键字参数会被传给所有 metaclass 的操作.
     19class 构造体被执行的时候,python 解释器按照下列顺序 interpretation,
     20         确定 class 对应的 metaclass ,
     21         准备 class 的 namespace,
     22         执行 class 定义体 - class body,
     23         创建 class 对象 - class object.
     24         
     25 
     26 下面我们逐一详细看一下儿以上几个解释步骤,
     27     metaclass 的确定 - Determining the appropriate metaclass
     28         metaclass 确定原则, 以 class B(metaclass = A, C) 为例阐述,
     29             如果 class 的定义中没有指定基类 bases, 并且没有 metaclass 关键字,采用 type() 作为 metaclass.
     30             如果有关键字 metaclass = A, 并且 A 不是 type() 的实例, 直接采用 A 作为 metaclass.
     31             如果 A 是 type() 一个实例 instance, 或者有定义基类 bases, 则 采用 the most derived metaclass  
     32             
     33             注,
     34                 candidate metaclasses 有2部分原来: 
     35                     a, metaclass 关键字, 如上例子中的 A 
     36                     b, 所有基类 bases的 metaclasses, 如上例子中的 type(c)  
     37                 the most derived metaclass 是 candidate metaclasses 集合中的一个, 
     38                 它需要满足是所有其他的 candidate 的 subtype,如果没有任何一个 candidate 满足这个条件,
     39class 的定义会报错,raise  TypeError  exception.
     40     
     41     namespace 的确定 - Preparing the class namespace
     42         metaclass 确定了之后, 到了该确定 namespace 的时候.
     43         如果 metaclass 有 __prepare__ attribute, 下面的语句将被调用,以确定 namespace
     44             namespace = metaclass.__prepare__(name, bases, **kwds), 
     45                 **kwds 来至于 class 的定义语句.   
     46         若 metaclass 没有 __prepare__ attribute, 则 类的 namespace 被初始化为空 an empty ordered mapping.
     47     
     48     class body 的执行 - Executing the class body
     49         class body 的执行, 可以用如下伪代码来表示,
     50             exec(body, globals(), namespace)
     51         
     52         跟一般的对 exec()的调用的关键区别在于, 当 class 定义在一个函数中时候,
     53         允许类的定义体 class body (包括其中的方法) 引用 '当前''外层' 作用域 scope 的 names
     54            "The key difference from a normal call to exec() is that lexical scoping allows 
     55             the class body (including any methods) to reference names from the current and
     56             outer scopes when the class definition occurs inside a function."
     57         然而,及时 class 被定义在一个函数中, 在 class scope 所定义的 names 对 class 中定义的 methods
     58         仍然不可见.
     59         对类变量 Class variables 的访问, 必须通过 self.variable 的形式访问,或作为第一个参数传入.
     60             即,
     61                 class A(object):
     62                     a =  "variable - a"
     63                     
     64                     def func1(self):         # 必须通过 self.variable 的形式访问 Class variables
     65                         print(self.a)
     66                     
     67                     def func2(self, a):       # 作为第一个参数传入的形式访问 Class variables   
     68                         print(a)
     69             
     70             再或者通过 隐式词法作用于 implicit lexically scoped __class__ 引用, 见下一节描述.
     71     
     72     class object 的创建 - Creating the class object            
     73         class namespace 被确定之后, class object 由下面方法创建,
     74             metaclass(name, bases, namespace, **kwds)
     75                 **kwds  跟传给 __prepare__ 的 **kwds, 即来至于 class 的定义语句.
     76         
     77         class object 即 super().__class__, 是一个在 class boby 中存在引用 __class__ 或 super 的方法
     78         的情况下儿被编译器 compiler 创建一个隐式闭包引用 an implicit closure reference.
     79         这保证了通过把 class 或者 instance 作为第一个参数来调用(属性/方法)的时候,无参数的 super() 
     80         可以正确的识别对应的 class, 即 class body 中的 self 机制.
     81     
     82         CPython implementation detail:
     83             从 python 3.6 开始, __class__ 被传给 metaclass 作为 __classcell__ 存储在类的 namespace 中.
     84             如果 __class__ 存在, 需要向上反推到 type.__new__ 的调用,以保证 class 的正确初始化.
     85             如果 type.__new__ 调用失败,将报告 DeprecationWarning, 之后报 RuntimeWarning (python 3.6).
     86             当采用默认 metaclass, 或某一 metaclass 调用了 type.__new__, 在创建了 class object 下面额外
     87             的步骤姜维调用,
     88                 a, type.__new__ 收集 class namespace 中的所有 descriptors, 定义 __set_name__() 方法
     89                 b, 在所定义的类上调用 __set_name__ 中的描述符方法,
     90                    class being defined and the assigned name of that particular descriptor 作为参数.
     91                 c, 在被定义 class 的最近的基类上(MRO)调用 __init_subclass__(),
     92class object 被创建后, 如果 class 存在 decorators 将 class object 传给 decorators 装饰.
     93             将返回的新对象绑定到 local namespace. 
     94             当一个新的 class 是由 type.__new__ 创建的, namespace parameter 复制一个新的 ordered mapping 
     95             中, 源对象被弃用. 新的 ordered mapping 将被包装成 read-only proxy, 最终成为 class object 的
     96             __dict__ 属性.  
     97             
     98 最后来看例子 - Metaclass example
     99     metaclasses 的潜在用途有很多, 包括  enum, logging, interface checking, automatic delegation, 
    100     automatic property creation, proxies, frameworks, and automatic resource locking/synchronization.
    101     
    102     下面是一个通过 collections.OrderedDict 来记录类参数定义顺序的 metaclasses 应用的例子, 
    103         import collections
    104         class OrderedClass(type):
    105 
    106             @classmethod
    107             def __prepare__(metacls, name, bases, **kwds):
    108                 return collections.OrderedDict()
    109         
    110             def __new__(cls, name, bases, namespace, **kwds):
    111                 result = type.__new__(cls, name, bases, dict(namespace))
    112                 result.members = tuple(namespace)
    113                 return result
    114         
    115         class A(metaclass=OrderedClass):
    116             A = 1
    117             C = 2
    118             B = 3
    119             def one(self): pass
    120             def two(self): pass
    121             def three(self): pass
    122             def four(self): pass
    123     Output,
    124         >>> A.members
    125         ('__module__', '__qualname__', 'A', 'C', 'B', 'one', 'two', 'three', 'four')
    126     
    127     当类 A 的定义体被执行的时候, 先调用 metaclass 的 __prepare__ 方法, __prepare__() 
    128     返回一个空的 collections.OrderedDict. 这个 OrderedDict 被用来按声明顺序记录 A 中
    129     定义的 methods and attributes. 当解释器解释到 attributes 被声明的位置时, 通过执行声明
    130     将 attributes 被添加到 ordered dictionary. 并且调用 metaclass 的 __new__() method 被, 
    131     结果就是 __new__() 创建一个新的的 type 并将 ordered dictionary 的 keys 存储在 members
    132     属性中.
    133 
    134 Reference,
    135     python doc,
    136         https://docs.python.org/3/reference/datamodel.html#metaclasses
  • 相关阅读:
    磁盘上没有足够的空间完成此操作的解决办法_Windows小知识
    使用XAMPP和DVWA在Windows7上搭建渗透测试环境
    使用WampServer和DVWA在Windows10上搭建渗透测试环境
    DOS系统常用命令
    Kali Linux图形界面与命令行界面的切换
    SQLMap入门之在Windows上安装SQLMap
    在Windows下同时安装Python2.x和Python3.x
    Python基础之Windows下Python3.x环境搭建
    在Linux上使用PGP签名验证文件完整性
    Ubuntu软件中心的完全启用
  • 原文地址:https://www.cnblogs.com/zzyzz/p/7763733.html
Copyright © 2011-2022 走看看