27. 元类

一、什么是元类

  在 Python 中,一切皆为对象,即类也是一个对象。type 是内置的元类。我们用 class 关键字定义的所有的类以及内置的类都是由元类 type(内置的元类) 实例化产生的。

class Person:

    def __init__(self, name, age):
        self.name = name
        self.age = age
  
    def show_info(self):
        print(f"name: {self.name}, age: {self.age}")

print(type(Person))
print(type(int))

当 Python 解释器遇到 class 的时候,实际上会进行调用,其目的是:至少要知道有哪些属性,有哪些方法,然后将这些类属性、方法传递到元类 type 中,进行创建一个对象,这个对象就是我们所谓的类对象。

二、class机制分析

# 1、类名
class_name = "Person"
# 2、类的基类
class_base = (object,)
# 3、执行类体代码拿到类的名称空间
class_dict = {"name": "unknown"}
class_body = """
def __init__(self, name, age):
    self.name = name
    self.age = age

def show_info(self):
    print(f"name: {self.name}, age: {self.age}")
"""

exec(class_body, {}, class_dict)
print(class_dict)

# 4、调用元类
Person = type(class_name, class_base, class_dict)
print(Person)

# 5、创建对象
p = Person("Sakura", 10)
p.show_info()
# 1、类名
class_name = "Person"
# 2、类的基类
class_base = (object,)
# 3、执行类体代码拿到类的名称空间
def show_info(self):
    print(f"name: {self.name}")

@classmethod
def description(cls):
    print(f"{cls.name}是一个人")

@staticmethod
def static():
    print("我是一个静态方法")

class_dict = {"name": "unknown", "show_info": show_info, "description": description, "static": static}

# 4、调用元类
Person = type(class_name, class_base, class_dict)
print(Person)

# 5、创建对象
p = Person()
p.show_info()
p.description()
p.static()

三、自定义元类

# 只有继承了type类的类才是元类
class MyMeta(type):

    # cls当前所在的类,*args、**kwargs调用类时所传入的参数
    def __new__(cls,*args,**kwargs):
        print("__new__()方法运行了")
        print(cls)
        print(args)
        print(kwargs)
        return type.__new__(cls, *args, **kwargs)

    # __init__()接收的参数是__new__()方法返回的
    def __init__(self, class_name, class_bases, class_dict):
        print("__init__()方法运行了")
        print(self)
        print(class_name)
        print(class_bases)
        print(class_dict)
  
    def __call__(self,*args,**kwargs):
        print(self)
        print(args)
        print(kwargs)
        # MyMeta.__call__()方法会先调用Person类内的__new__()方法
        obj = self.__new__(self)
        # MyMeta.__call__()方法内会调用Person类内的__init__()方法
        self.__init__(obj,*args,**kwargs)
        # MyMeta.__call__()方法会返回一个初始化好的对象
        return obj

"""
调用MyMeta发生的三件事:
    1、先造一个空对象,调用类内的__new__()方法,就是调用type.__call__()方法
    2、调用MyMeta这个类内的__init__()方法,完成初始化对象的操作
    3、返回初始化好的对象
Person = MyMeta(class_name,class_bases,class_dict)
"""

"""
类的产生:Person = MyMeta() --> type.__call__()干的三件事:
    1、type.__call__()方法内会先调用MyMeta类内的__new__()方法
    2、type.__call__()方法内会调用MyMeta类内的__init__()方法
    3、type.__call__()方法会返回一个初始化好的对象
"""
class Person(metaclass=MyMeta):

    def __new__(cls,*args,**kwargs):
        # 产生真正的对象
        return object.__new__(cls)

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

    def show_info(self):
        print(f"name: {self.name}, age: {self.age}")

"""
类的调用:p = Person("Sakura",10) --> MyMeta.__call__()干的三件是
    1、MyMeta.__call__()方法内会先调用Person类内的__new__()方法
    2、MyMeta.__call__()方法内会调用Person类内的__init__()方法
    3、MyMeta.__call__()方法会返回一个初始化好的对象
"""
p = Person("Sakura",10)
print(p)
print(p.__dict__)
# 只有继承了type类的类才是元类
class MyMeta(type):
    def __new__(cls, class_name, class_base, class_dict):
        print("__new__()方法运行了")
        # 方法1:通过type来做类对象的创建
        return type(class_name, class_base, class_dict)
        # 方法2:复用type.__init__()方法
        #return type.__new__(cls, class_name, class_base, class_dict)

class Person(metaclass=MyMeta):
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def show_info(self):
        print(f"name: {self.name}, age: {self.age}")

p = Person("Sakura",10)
print(p)
print(p.__dict__)

只要调类,那么会依次调用类内的 __new__() 方法,在调用 __init__() 方法;

如果想要一个对象可以加括号调用,需要在该对象的类中添加一个 __call__() 方法;

四、利用元类实现单例模式

class MyType(type):
  
    def __init__(self, name, base, attrs):
        super().__init__(name, base, attrs)
        self.instance = None

    def __call__(self, *args, **kwargs):
        # 判断是否有对象,有,则不创建,没有,则创建
        if not self.instance:
            # 调用自己的那个类的__new__()创建对象
            self.instance = self.__new__(self)

        # 调用自己的那个类的__init__()初始化对象
        self.__init__(self.instance, *args, **kwargs)

        return self.instance
  
class P(metaclass=MyType):
    pass

p1 = P()
print(p1)

p2 = P()
print(p1)
posted @ 2024-11-03 18:26  星光映梦  阅读(6)  评论(0编辑  收藏  举报