• 来看看Python MetaClass元类详解


    MetaClass元类,本质也是一个类,但和普通类的用法不同,它可以对类内部的定义(包括类属性和类方法)进行动态的修改。可以这么说,使用元类的主要目的就是为了实现在创建类时,能够动态地改变类中定义的属性或者方法。

    不要从字面上去理解元类的含义,事实上 MetaClass 中的 Meta 这个词根,起源于希腊语词汇 meta,包含“超越”和“改变”的意思。

    举个例子,根据实际场景的需要,我们要为多个类添加一个 name 属性和一个 say() 方法。显然有多种方法可以实现,但其中一种方法就是使用 MetaClass 元类。

    如果在创建类时,想用 MetaClass 元类动态地修改内部的属性或者方法,则类的创建过程将变得复杂:先创建 MetaClass 元类,然后用元类去创建类,最后使用该类的实例化对象实现功能。

    和前面章节创建的类不同,如果想把一个类设计成 MetaClass 元类,其必须符合以下条件:

    1. 必须显式继承自 type 类;
    2. 类中需要定义并实现 __new__() 方法,该方法一定要返回该类的一个实例对象,因为在使用元类创建类时,该 __new__() 方法会自动被执行,用来修改新建的类。


    讲了这么多,读者可能对 MetaClass 元类的功能还是比较懵懂。没关系,我们先尝试定义一个 MetaClass 元类:

     
    
    1. #定义一个元类
    2. class FirstMetaClass(type):
    3. # cls代表动态修改的类
    4. # name代表动态修改的类名
    5. # bases代表被动态修改的类的所有父类
    6. # attr代表被动态修改的类的所有属性、方法组成的字典
    7. def __new__(cls, name, bases, attrs):
    8. # 动态为该类添加一个name属性
    9. attrs['name'] = "C语言中文网"
    10. attrs['say'] = lambda self: print("调用 say() 实例方法")
    11. return super().__new__(cls,name,bases,attrs)

    此程序中,首先可以断定 FirstMetaClass 是一个类。其次,由于该类继承自 type 类,并且内部实现了 __new__() 方法,因此可以断定 FirstMetaCLass 是一个元类。

    有关 __new__() 的具体用法,可阅​ 读《Python __new__()方法》一节。 ​

    可以看到,在这个元类的 __new__() 方法中,手动添加了一个 name 属性和 say() 方法。这意味着,通过 FirstMetaClass 元类创建的类,会额外添加 name 属性和 say() 方法。通过如下代码,可以验证这个结论:

     
    
    1. #定义类时,指定元类
    2. class CLanguage(object,metaclass=FirstMetaClass):
    3. pass
    4. clangs = CLanguage()
    5. print(clangs.name)
    6. clangs.say()

    可以看到,在创建类时,通过在标注父类的同时指定元类(格式为metaclass=元类名)​ ,则当 Python 解 ​释器在创建这该类时,FirstMetaClass 元类中的 __new__ 方法就会被调用,从而实现动态修改类属性或者类方法的目的。

    运行上面的程序,输出结果为:

    C语言中文网
    调用 say() 实例方法

    显然,FirstMetaClass 元类的 __new__() 方法动态地为 Clanguage 类添加了 name 属性和 say() 方法,因此,即便该类在定义时是空类,它也依然有 name 属性和 say() 方法。

    对于 MetaClass 元类,它多用于创建 API,因此我们几乎不会使用到它。

  • 相关阅读:
    【JavaWeb学习】—手托html页面和在浏览器中输入地址访问的背后不同原因(十一)
    不同环境下RabbitMQ的安装-2 ARM架构、X86架构、Window系统环境下安装RabbitMQ
    CISSP学习笔记: 事件与道德规范
    【实用 Python 库】使用 XPath 与 lxml 模块在 Python 中高效解析 XML 与 HTML
    pandas通过DatetimeProperties对象获取日期对象是否是所在季度的第一天(is quarter start)
    智能家居涉及到的12个物联网传感器!
    关于proxmox,给Zstack的公开建议
    【Java】初识IO流【附导航】
    PaddleOCRv3之三:rec识别部分训练
    shell学习脚本04(小滴课堂)
  • 原文地址:https://blog.csdn.net/weixin_42673574/article/details/132918734