一、通过元类创建类
#!/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