• Python类和对象创建过程分析与元类以及魔法函数


    一. 类以及实例生成流程说明:

    1. 元类处理
    • 父类生成

    MyMeta.__prepare__
    MyMeta.__new__
    MyMeta.__init__

    • 子类生成

    MyMeta.__prepare__
    MyMeta.__new__

    MyClass.__init_subclass__ 在元类的new函数中隐藏调用了父类的init_subclass函数

    MyMeta.__init__
    MyMeta.__call__ 隐藏调用了子类的__new__和__init__

    MyDerivedClass.__new__

    MyClass.__new__(子类明确调用了父类的new)

    MyDerivedClass.__init__

    MyClass.__init__(子类明确调用了父类的init)

    二. 代码演示:

    
    import functools
    
    
    __all__ = ("my_decorator", "MyMeta", "MyBase", "MyClass", "MyDerivedClass",
               "main_run")
    
    
    def __dir__():
        return __all__
    
    
    def my_decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            args_str = ", ".join(map(str, args))
            kwargs_str = ", ".join(map(lambda kv: "=".join(map(str, kv)),
                                       kwargs.items()))
            if args_str and kwargs_str:
                all_str = ", ".join((args_str, kwargs_str))
            else:
                all_str = args_str + kwargs_str
    
            func_call_prompt = f"{func.__qualname__}({all_str})"
            print(f"{func_call_prompt}, Begin...")
            result = func(*args, **kwargs)
            print(f"{func_call_prompt}={result}, End!")
            return result
        return wrapper
    
    
    class MyMeta(type):
        """"""
        @my_decorator
        def __new__(mcs, what, bases=None, cls_dict=None, **kwargs):
            """mcs:指的是本元类"""
            new_dict = {}
            new_dict.update(cls_dict)
            new_dict.update(kwargs)
            return super().__new__(mcs, what, bases, new_dict)
    
        @my_decorator
        def __init__(cls, what, bases=None, cls_dict=None, **kwargs):
            """cls:指要生成的类,函数参数是这种样式,可以参见type.__init__定义"""
            super().__init__(what, bases, cls_dict)
    
        @my_decorator
        def __call__(cls, *args, **kwargs):
            """cls:指要生成的类,*args, **kwargs是类的__init__函数参数"""
            return super().__call__(*args, **kwargs)
    
        @classmethod
        @my_decorator
        def __prepare__(mcs, name, bases, **kwargs):
            print(mcs, name, bases, kwargs)
            return super().__prepare__(name, bases, **kwargs)
    
    
    class MyBase:
        pass
    
    
    class MyClass(MyBase, metaclass=MyMeta, class_id=1234):
        name = ""
    
        @my_decorator
        def __new__(cls, *args, **kwargs):
            """mcs:指的是本元类"""
            return super().__new__(cls)
    
        @my_decorator
        def __init__(self, name="", age=0):
            self.age = age
            self.name = name
    
        @my_decorator
        def __call__(self, *args, **kwargs):
            print("MyClass.__call__ working")
    
        @my_decorator
        def __init_subclass__(cls, **kwargs):
            print(cls, kwargs)
    
    
    class MyDerivedClass(MyClass, tag="div"):
        tag = ""
    
        @my_decorator
        def __new__(cls, *args, **kwargs):
            """mcs:指的是本元类"""
            return super().__new__(cls)
    
        @my_decorator
        def __init__(self, name="", age=0, height=0):
            super().__init__(name, age)
            self.height = height
    
        @my_decorator
        def __call__(self, *args, **kwargs):
            super().__call__(*args, **kwargs)
            print("MyDerivedClass.__call__ working")
    
    
    @my_decorator
    def hello(*args, **kwargs):
        print(args, kwargs)
    
    
    def main_run():
        """主函数"""
        my = MyDerivedClass("Tom", age=56)
        print(my.class_id, my.tag)
        my()
    
    
    if __name__ == "__main__":
        main_run()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117

    结果输出:

    MyMeta.__prepare__(, MyClass, (,), class_id=1234), Begin...
     MyClass (,) {'class_id': 1234}
    MyMeta.__prepare__(, MyClass, (,), class_id=1234)={}, End!
    MyMeta.__new__(, MyClass, (,), {'__module__': '__main__', '__qualname__': 'MyClass', 'name': '', '__new__': ...}, class_id=1234), Begin...
    MyMeta.__new__(, MyClass, (,), {'__module__': '__main__', '__qualname__': 'MyClass', 'name': '', '__new__': ...}, class_id=1234)=, End!
    MyMeta.__init__(, MyClass, (,), {'__module__': '__main__', '__qualname__': 'MyClass', 'name': '', '__new__': ...}, class_id=1234), Begin...
    MyMeta.__init__(, MyClass, (,), {'__module__': '__main__', '__qualname__': 'MyClass', 'name': '', '__new__': ...}, class_id=1234)=None, End!
    MyMeta.__prepare__(, MyDerivedClass, (,), tag=div), Begin...
     MyDerivedClass (,) {'tag': 'div'}
    MyMeta.__prepare__(, MyDerivedClass, (,), tag=div)={}, End!
    MyMeta.__new__(, MyDerivedClass, (,), {'__module__': '__main__', '__qualname__': 'MyDerivedClass', 'tag': '', '__new__': ...}, tag=div), Begin...
    MyClass.__init_subclass__(), Begin...
     {}
    MyClass.__init_subclass__()=None, End!
    MyMeta.__new__(, MyDerivedClass, (,), {'__module__': '__main__', '__qualname__': 'MyDerivedClass', 'tag': '', '__new__': ...}, tag=div)=, End!
    MyMeta.__init__(, MyDerivedClass, (,), {'__module__': '__main__', '__qualname__': 'MyDerivedClass', 'tag': '', '__new__': ...}, tag=div), Begin...
    MyMeta.__init__(, MyDerivedClass, (,), {'__module__': '__main__', '__qualname__': 'MyDerivedClass', 'tag': '', '__new__': ...}, tag=div)=None, End!
    MyMeta.__call__(, Tom, age=56), Begin...
    MyDerivedClass.__new__(, Tom, age=56), Begin...
    MyClass.__new__(), Begin...
    MyClass.__new__()=<__main__.MyDerivedClass object ...>, End!
    MyDerivedClass.__new__(, Tom, age=56)=<__main__.MyDerivedClass object at ...>, End!
    MyDerivedClass.__init__(<__main__.MyDerivedClass object at ...>, Tom, age=56), Begin...
    MyClass.__init__(<__main__.MyDerivedClass object at ...>, Tom, 56), Begin...
    MyClass.__init__(<__main__.MyDerivedClass object at ...>, Tom, 56)=None, End!
    MyDerivedClass.__init__(<__main__.MyDerivedClass object at ....>, Tom, age=56)=None, End!
    MyMeta.__call__(, Tom, age=56)=<__main__.MyDerivedClass object at ...>, End!
    1234 div
    MyDerivedClass.__call__(<__main__.MyDerivedClass object at ...>), Begin...
    MyClass.__call__(<__main__.MyDerivedClass object at ...>), Begin...
    MyClass.__call__ working
    MyClass.__call__(<__main__.MyDerivedClass object at ...>)=None, End!
    MyDerivedClass.__call__ working
    MyDerivedClass.__call__(<__main__.MyDerivedClass object at ...>)=None, End!
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    (一) 明确几个概念:

    1. 实例是由对象生成的,调用对象的__new__创建实例内存,调用对象的__init__初始化实例的属性
    2. 类是type的实例:type(OtherClass)都是type,表示类是type的实例
    3. 缺省(顶层)的元类是type,默认创建的类的元类都是type
    4. 其他自定义元类都是type的派生类。
    5. 其他类都是object的派生类。

    (二) 当没有类实例创建时

    此时,只存在类的创建,这时候类相当于元类(缺省时type)的实例,而实例的创建时调用对象的__new__和__init__

    def main_run():
        """主函数"""
    
    • 1
    • 2

    输出如下:

    MyMeta.__new__(  MyClass (,) {'__module__': '__main__', '__qualname__': 'MyClass', 'name': '', '__new__': , '__init__': , '__call__': , '__classcell__': } ) Begin...
    MyMeta.__new__(  MyClass (,) {'__module__': '__main__', '__qualname__': 'MyClass', 'name': '', '__new__': , '__init__': , '__call__': , '__classcell__': } ) End!
    MyMeta.__init__(  MyClass (,) {'__module__': '__main__', '__qualname__': 'MyClass', 'name': '', '__new__': , '__init__': , '__call__': , '__classcell__': } ) Begin...
    MyMeta.__init__(  MyClass (,) {'__module__': '__main__', '__qualname__': 'MyClass', 'name': '', '__new__': , '__init__': , '__call__': , '__classcell__': } ) End!
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (三) 当创建了类实例时

    创建类实例(将类,元类的实例作为可调用对象进行调用),相当于调用了元类的__call__,call__中调用了类的__new__和__init

    def main_run():
        """主函数"""
        my = MyClass("Tom", age=56)
    
    • 1
    • 2
    • 3

    输出如下:

    MyMeta.__new__(  MyClass (,) {'__module__': '__main__', '__qualname__': 'MyClass', 'name': '', '__new__': , '__init__': , '__call__': , '__classcell__': } ) Begin...
    MyMeta.__new__(  MyClass (,) {'__module__': '__main__', '__qualname__': 'MyClass', 'name': '', '__new__': , '__init__': , '__call__': , '__classcell__': } ) End!
    MyMeta.__init__(  MyClass (,) {'__module__': '__main__', '__qualname__': 'MyClass', 'name': '', '__new__': , '__init__': , '__call__': , '__classcell__': } ) Begin...
    MyMeta.__init__(  MyClass (,) {'__module__': '__main__', '__qualname__': 'MyClass', 'name': '', '__new__': , '__init__': , '__call__': , '__classcell__': } ) End!
    MyMeta.__call__(  ('Tom',) {'age': 56} ) Begin...
    MyClass.__new__(:  ('Tom',) {'age': 56} ) Begin...
    MyClass.__new__(:  ('Tom',) {'age': 56} ) End!
    MyClass.__init__( <__main__.MyClass object at 0x0000026AD903F910> Tom 56 ) Begin...
    MyClass.__init__( <__main__.MyClass object at 0x0000026AD903F910> Tom 56 ) End!
    MyMeta.__call__(  ('Tom',) {'age': 56} ) End!
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    (四) 当调用了类实例的对象时

    类实例作为可调用对象,进行调用

    def main_run():
        """主函数"""
        my = MyClass("Tom", age=56)
        my()
    
    • 1
    • 2
    • 3
    • 4

    输出如下:

    MyMeta.__new__(  MyClass (,) {'__module__': '__main__', '__qualname__': 'MyClass', 'name': '', '__new__': , '__init__': , '__call__': , '__classcell__': } ) Begin...
    MyMeta.__new__(  MyClass (,) {'__module__': '__main__', '__qualname__': 'MyClass', 'name': '', '__new__': , '__init__': , '__call__': , '__classcell__': } ) End!
    MyMeta.__init__(  MyClass (,) {'__module__': '__main__', '__qualname__': 'MyClass', 'name': '', '__new__': , '__init__': , '__call__': , '__classcell__': } ) Begin...
    MyMeta.__init__(  MyClass (,) {'__module__': '__main__', '__qualname__': 'MyClass', 'name': '', '__new__': , '__init__': , '__call__': , '__classcell__': } ) End!
    MyMeta.__call__(  ('Tom',) {'age': 56} ) Begin...
    MyClass.__new__(:  ('Tom',) {'age': 56} ) Begin...
    MyClass.__new__(:  ('Tom',) {'age': 56} ) End!
    MyClass.__init__( <__main__.MyClass object at 0x0000026AD903F910> Tom 56 ) Begin...
    MyClass.__init__( <__main__.MyClass object at 0x0000026AD903F910> Tom 56 ) End!
    MyMeta.__call__(  ('Tom',) {'age': 56} ) End!
    MyClass.__call__(: <__main__.MyClass object at 0x0000026AD903F910> () {} ) Begin...
    MyClass.__call__ working
    MyClass.__call__(: <__main__.MyClass object at 0x0000026AD903F910> () {} ) End!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    三、总结:

    1. 根据调用顺序,如果上层足够使用(__init__, __int_subclass__, __new__),
      就不使用底层的知识(元类)
    2. 慎用元类编程, 谷歌对这方面的使用要审批。
    3. 需要分析具体的使用场景,然后选择合适的魔法函数进行使用
  • 相关阅读:
    MySQL事务篇
    MobPush丨Android端SDK API
    GIS Office国产基础软件,助力移动通信基础资源管理建设工程
    MyBatis动态SQL多表操作
    5.1 Stream介绍和实战
    计算机毕业设计Java微博系统网站(源码+系统+mysql数据库+Lw文档)
    【BP时序预测】基于鱼鹰算法OOA优化BP神经网络实现温度数据预测算法研究附matlab代码
    字节跳动大数据研发面试——自我反省
    企业电子招标采购系统源码之从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理
    java-php-python-ssm外卖订餐管理计算机毕业设计
  • 原文地址:https://blog.csdn.net/mengyoufengyu/article/details/127895544