元类回顾

什么是元类?

**最本质的概念: **能够实例化产生类的类,就是元类; type是python解释器内置的元类

或继承type这个类的类就是元类(自定义的元类)

class关键字底层原理: 通过type类来实例化得到类

调用了type()

只传一个参数有什么用?

打印这个对象的类型

print(type(1))		# 结果为: <class 'int'>

传三个参数就是class关键字的底层原理

def __init__(self, name):
    self.name=name
Person = type('Person', (object,), {'a': 3, '__init__': __init__})
p = Person('nick')
p.name
# 等同于
class Person(object,):
    a = 3
    def __init__(self, name):
        self.name=name

exec 就是执行字符串的代码, 当成Python解释器

ss = '''
x = 1
print(x)
'''
g = {}
l = {}
exec(ss, g, l)

自定义元类: 来控制类的产生; 继承type

class My_class(type):
    def __init__(self, name, bases, dic):
        # 如果dic里面没有name属性,抛出错误
        a = dic.get('name')
        if a:
            raise Exception('没有name属性,不可创建')
   	
    def __call__(self, *args, **kwargs):
        pass

class Person(metaclass=My_class):		# Person = MY_class('Person', (object,), {...})   My_class类实例化, 会把三个参数传到My_class的__init__方法中
    def __init__(self, name ):
        self.name = name
       
p = Person('hys')		# Person()	类实例化的时候会自动触发Person类的__init__的执行

更深层的意思

class My_class(type):
    def __init__(self, name, bases, dic):
        # self  是Person	 这个类(对象)
        print(self.__dict__)		# 相当于Person.__dict__
        # 在这个位置,其实self也就是说Person这个类,内部已经有东西了,名称空间已经有东西了
        # 所以在这个地方,可以通过dic来判断名称空间
        # 也可以直接通过self.__dict__/self.name(属性)来判断
        
        # 如果dic里面没有name属性,抛出错误
        a = dic.get('name')
        if a:
            raise Exception('没有name属性,不可创建')

    def __call__(self, *args, **kwargs):
        pass

class Person(metaclass=My_class):  # Person = MY_class('Person', (object,), {...})   My_class类实例化, 会把三个参数传到My_class的__init__方法中
    def __init__(self, name):
        self.name = name

print(Person.__dict__)

p = Person('hys')  # Person()	类实例化的时候会自动触发Person类的__init__的执行

总结:可以通过自定义元类,重写__init__方法来控制类的产生

通过元类控制类的调用过程, 实例化产生对象的过程

class My_class(type):
    def __call__(self, *args, **kwargs):
        # 该方法必须返回一个对象(类对象)吗, 这个地方return返回什么 p=Person('hys')	p就是什么
        
        # 第一步:产生一个空对象
        # object.__new__(self)  传一个参数(类), 就会产生一个该类的空对象
        obj = object.__new__(self)			# obj 是Person类的空对象
        print(self.__new__ is object.__new__)	# True
        
        # 第二步:初始化该对象, 把初始值放到对象中
        # 因为 obj 是Person类的空对象, obj.__init__ 调用自己的绑定方法, 也就是说Person类中写的__init__方法
        obj.__init__(*args, **kwargs)
        # 还可以类来调用
        # Person.__init__(obj, *args, **kwargs)
        self.__init__(obj, *args, **kwargs)
        
        # 第三步:把该对象返回
        return obj

class Person(metaclass=My_class):
# class Person():
    def __init__(self, name ):
        self.name = name
    def __call__(self, *args, **kwargs):
        print('sbsh')
       
#原来的理解:Person('hys')  会调用Person类的__init__方法
#有了元类后:这个位置首先会调用元类的__call__方法, 所以再__call__方法中调用了Person类的__init__方法,来完成对象的初始化
p = Person('hys')
p()		# 这个位置会调用类的__call__方法

模板:控制对象的产生

class My_class(type):
    def __call__(self, *args, **kwargs):
        obj = object.__new__(self)
        obj.__init__(*args, **kwargs)
        return obj

class Person(metaclass=My_class):
    def __init__(self, name ):
        self.name = name
    def __call__(self, *args, **kwargs):
        print('sbsh')

p = Person('hys')

作业: 把实例化传的参数,定义成字典的形式

class My_class(type):
    def __call__(self, name, age):
        obj = object.__new__(self)
        # obj.__init__(*args, **kwargs)
        obj.__dict__['attr']=['name':name, 'age': age]
        return obj

class Person(metaclass=My_class):
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __call__(self, *args, **kwargs):
        print('sbsh')

p = Person('hys', age)
# 这样才能拿到
print(p.attr[name])
# 不用init方法,但是能完成对象的初始化

练习:

  1. 在元类中控制把自定义类的数据属性都变成大写

  2. 在元类中控制自定义的类无需__init__方法

    1.元类帮其完成创建对象,以及初始化操作;

    2.要求实例化时传参必须为关键字形式,否则抛出异常TypeError: must use keyword argument

    3.key作为用户自定义类产生对象的属性,且所有属性变成大写

  3. 在元类中控制自定义的类产生的对象相关的属性全部为隐藏属性

  4. 基于元类实现单例模式

posted @ 2023-10-30 11:22  hanyingshuo  阅读(24)  评论(0)    收藏  举报