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()

结果输出:

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

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

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

def main_run():
    """主函数"""

输出如下:

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!

(三) 当创建了类实例时

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

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

输出如下:

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!

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

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

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

输出如下:

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. 根据调用顺序,如果上层足够使用(__init__, __int_subclass__, __new__),
    就不使用底层的知识(元类)
  2. 慎用元类编程, 谷歌对这方面的使用要审批。
  3. 需要分析具体的使用场景,然后选择合适的魔法函数进行使用

你可能感兴趣的:(python,python,开发语言)