• 元类(转自https://zhuanlan.zhihu.com/p/23887627)


    虽然Python本身很难说是面向对象语言,但Python中的数据模型(data model)可以说真的是“纯面向对象”。在Python的世界里,一切皆是对象。无论是数值、字符串、序列、字典、函数、模块、类、实例、文件等等。

    元类(metaclass)是Python 2.2中引入的概念,它的作用是定制类的创建行为。这么解释可能有点难理解,那么这篇文章就通过实例,一步步解释Python中的元类。



    1. Python中一切皆对象,包括类

    class Foo:
    def hello(self):
    print("hello world!")
    return
    
    foo = Foo()
    print(type(foo))            # <class '__main__.Foo'>
    print(type(foo.hello))      # <class 'method'>
    print(type(Foo))            # <class 'type'>
    
    temp = Foo                  # 赋值给其他变量
    Foo.var = 11                # 增加参数
    print(Foo)                  # 作为函数参数
    

    例子中type(Foo)说明Foo本身也是一个对象,可以将其赋值给其他对象、对其添加属性、将其作为函数参数传递等等。



    2. 类的创建过程

    在上边的例子中,类Foo的创建过程中会执行class语句,此时需要首先确定元类(元类定制类的创建行为)。元类的确定过程如下:

    • 确定类Foo的父类是否有参数metaclass,如果没有则:
    • 确定类Foo的父类的父类是否有参数metaclass,如果没有则:
    • 使用默认元类type(type的用法会在3中讲解)。

    上边的例子中,前2项都不符合,则直接使用默认元类type。即上边的语句相当于:

    def hello(self):
        print("hello world")
        return
    
    Foo = type("Foo", (object,), {"hello": hello})
    

    此时可以看出,实际上类Foo是元类type的实例。参见文章的封面图。



    3. 动态创建类

    Python中的类可以动态创建,用的就是默认元类type。动态创建类的type函数原型为:

    type(object_or_name, bases, dict)
    

    这里不过多赘述,上个章节中有介绍。举个比较复杂的动态创建类的例子:

    def init(self, name):
        self.name = name
    return
    
    def hello(self):
    print("hello %s" % self.name)
    return
    
    Foo = type("Foo", (object,), {"__init__": init, "hello": hello, "cls_var": 10})
    foo = Foo("xianhu")
    print(foo.hello())
    print(Foo.cls_var)
    

    4. 自定义元类

    再一次说明实例、类和元类之间的关系:

    >>> foo.__class__     # <class 'Foo'>
    >>> Foo.__class__     # <class 'type'>
    >>> type.__class__    # <class 'type'>
    

    foo是Foo的实例,Foo是type的实例,type的类又是type。type是默认的元类。那么如何自定义元类呢?(注意,百分之99的工程中不会用到自定义元类,除非你对元类非常理解)

    举个例子,假设我们需要对一个模块中的所有函数添加作者属性。首先自定义一个元类,自定义时,需要继承默认元类type,并重写其中的__new__方法:

    class Author(type):
        def __new__(mcs, name, bases, dict):
            # 添加作者属性
            dict["author"] = "xianhu"
            return super(Author, mcs).__new__(mcs, name, bases, dict)
    

    对模块中所有函数的继承类参数中添加metaclass参数:

    class Foo(object, metaclass=Author):
        pass
    
    foo = Foo()
    print(foo.author)
    

    注意:Python3中不再有__metaclass__属性以及模块级别的__metaclass__属性。如果一个模块中函数较多,可以利用正则表达式进行查找替换。

    不过在平时的使用中,我发现了模块级别有个__build_class__函数,将其改为Author,就能达到模块级别元类的效果。但具体有哪些副作用还不太清楚,慎用!!!

  • 相关阅读:
    修改ubuntu14.04命令行启动
    python 配置文件读写
    platform模块
    PowerDesigner简单使用记录
    python中的pika模块
    RSync实现文件备份同步
    Tornado web 框架
    psutil模块
    .sort与sorted的区别
    Python __len__()、__reversed__()、__contains__()
  • 原文地址:https://www.cnblogs.com/coco-shi/p/9927443.html
Copyright © 2020-2023  润新知