元类创建类的流程详解

一、通过元类创建类

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024-04-07 20:40
# @Author  : Maple
# @File    : 001-元类创建类的流程.py

"""
1. MyMeta的 __init__方法在类创建时被调用,而不是在类的实例创建时调用。
 当你定义一个类,并且这个类使用了元类(通过 metaclass 关键字指定),Python 首先会通过元类的 __new__ 方法创建类对象,
   然后调用元类的 __init__ 方法来初始化这个刚刚创建的类对象。

2. MyMeta的_call__ 在类的实例创建时被调用。
  __call__ 方法实际上控制着类实例的创建过程,它会调用类(是指被创建的类)的 __new__ 方法来创建实例,
   然后调用类的的 __init__ 方法来初始化。

"""


class MyMeta(type):
    # 用来创建类,只在定义的时候运行一次
    # cls是表示被创建的类(此例中是MyClass)
    # name是表示正在被创建的类的名称)--此例中是MyClass
    # bases:元组,包含了类的所有基类。
    # 包含了类定义中的所有属性和方法。
    def __init__(cls, name, bases, class_dict):
        # cls是要创建的类-此例是MyClass
        print(f"{cls.__name__} __init__ for {name}")
        # 1.type类首先会通过元类的__new__方法,创建实例对象(只不过这里的实例比较特殊-是一个类)
        # 2.然后调用type的init方法来初始化上面步骤创建的那个类(此例中就是 MyClass )
        super().__init__(name, bases, class_dict)

    def __call__(cls, *args, **kwargs):
        print(f"MyMeta __call__ for {cls.__name__}") # MyMeta __call__ for MyClass
        print('super:',super.__class__) # type
        # 调用type类的call方法来创建是类(是指Myclass)的实例
        """ 这个过程涉及到调用类的 __new__ 方法来分配内存
           然后调用 __init__ 方法来初始化新创建的实例
        """
        return super().__call__(*args, **kwargs)

class MyClass(metaclass=MyMeta):
    def __init__(self):
        print("MyClass __init__")

if __name__ == '__main__':

    pass

# 类定义时
# 输出: MyMeta __init__ for MyClass

# 类实例化时
instance = MyClass()
# 输出:
# MyMeta __call__ for MyClass
# MyClass __init__

二、应用举例

包含不允许实例化对象以及实现单例对象两个例子

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024-04-07 17:43
# @Author  : Maple
# @File    : 13-使用元类控制实例的创建.py

"""
元类是type类的子类
"""

class NoInstance(type):
    def __call__(self, *args, **kwargs):
        raise TypeError("can't instanciate directly")

class Person(metaclass=NoInstance):

    def __init__(self,name):
        self.name = name

    @staticmethod
    def run():
        print('grok is running')


"""利用元类实现单列模式
"""

class Singleton(type):

    # init方法是完成类(此例中是 Student )的初始化
    # self表示Student类, self.__instance即为类添加了一个类属性
    def __init__(self,*args,**kwargs):
        # self代表元类Singleton的实例(注意元类是用来创建类的,因此其实例对象是一个类)
        # 因此,此例中self代表Student类
        self.__instance = None
        # super()代表type
        """
        *args 和 **kwargs:这些是位置参数和关键字参数的列表,它们在创建类对象时被传递给 type 的构造函数。通常,这些参数包括:
        
        name:字符串,代表正在被创建的类的名称。
        bases:元组,包含了类的所有基类。
        class_dict:字典,包含了类定义中的所有属性和方法。
        """
        print('__init__方法中的args')
        for a in args:
            print('a: ',a)

        # 调用type的init方法,初始化需要创建的类(在此之前其实会先调用new方法,真正创建类,然后实现初始化)
        super().__init__(*args,**kwargs)


    # 当要创建的类(此例中是 Student 类) 实例化时,会调用元类的call方法
    def __call__(self, *args, **kwargs):
        #
        if self.__instance is None:
            print('__call__方法中的args')
            """
            a:  Maple
            a:  19
            """
            for a in args:
                print('a: ', a)

            # 调用type的call方法,返回一个实例对象(student),并存放在Student类的__instance属性中
            # self是Student类
            self.__instance = super().__call__(*args,**kwargs)
            return self.__instance
        else:
            return self.__instance


class Student(metaclass=Singleton):
    def __init__(self,name,age):
        self.name = name
        self.age = age



if __name__ == '__main__':

    # 1. Person不能被实例化,run方法只能通过类调用
    print('******** 1. Person不能被实例化,run方法只能通过类调用***************')
    Person.run() # grok is running

    try:
        p = Person('Maple')
    except TypeError as e:
        print(e) # can't instanciate directly


    print('********2. 单例测试****************')
    ## 2-1 类属性查看
    print(Student.__dict__) #  {...Singleton__instance': None}

    ## 2-2 初始化实例对象
    s1 = Student('Maple',19)
    print(Student.__dict__)  # {..._Singleton__instance': <__main__.Student object at 0x00000180EB622D80>}}
    s2 = Student('Maple', 19)
    print(Student.__dict__)  # {..._Singleton__instance': <__main__.Student object at 0x00000180EB622D80>}}
    print(s1 is s2) # True

相关推荐

  1. 创建流程详解

    2024-04-08 07:40:02       40 阅读
  2. C++超详细知识点(五):函数和友

    2024-04-08 07:40:02       42 阅读
  3. python中

    2024-04-08 07:40:02       39 阅读
  4. python子继承基

    2024-04-08 07:40:02       40 阅读
  5. 详解QUuid使用

    2024-04-08 07:40:02       40 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-08 07:40:02       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-08 07:40:02       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-08 07:40:02       87 阅读
  4. Python语言-面向对象

    2024-04-08 07:40:02       96 阅读

热门阅读

  1. 【测试开发学习历程】python函数

    2024-04-08 07:40:02       31 阅读
  2. C语言学习分享

    2024-04-08 07:40:02       28 阅读
  3. 什么是物联网?

    2024-04-08 07:40:02       38 阅读
  4. 小程序View点击响应传递多个参数

    2024-04-08 07:40:02       34 阅读
  5. 微信小程序脚本的执行顺序

    2024-04-08 07:40:02       32 阅读
  6. KADB锁冲突查看及解决

    2024-04-08 07:40:02       33 阅读
  7. 金融数据_Scikit-Learn决策树(DecisionTreeClassifier)实例

    2024-04-08 07:40:02       32 阅读
  8. 【面经】软件开发工程师-后端方向1

    2024-04-08 07:40:02       27 阅读
  9. 2024-04-07(复盘前端)

    2024-04-08 07:40:02       32 阅读