Python之元类

本文介绍了Python中的元类,它是生成类的类,用于定制类的产生过程。元类的`__init__`和`__call__`方法展示了如何在类的创建和实例化阶段进行定制。通过学习元类,可以实现对类和对象行为的高级控制。

Python之元类

什么是元类?

即产生类的类就是元类,我们可以推导一下

可以先推导一下
'''
基础阶段我们使用type来查看数据的数据类型
但是现在我们学了面向对象后,发现其实本质是查看数据所属的类,而不是数据类型
'''
s = 'hello world'
l = ['hello']
d = {'name':'jack'}
i = 123

print(type(s))  # <class 'str'>
print(type(l))  # <class 'list'>
print(type(d))  # <class 'dict'>
print(type(i))  # <class 'int'>
'''
我们可以发现我们最开始学的type内置方法,查出来的时一个数据类的数据名
所以我们可以确定type方法是用来看产生对象的类名
'''
class Myclass():
    pass

obj = Myclass()
print(type(obj))  # <class '__main__.Myclass'>

'''确定type方法可以看产生对象的类名,那么可以查看类名会显示什么'''
print(type(Myclass))  # <class 'type'>
'''可以得出结论,我们定义的类其实都是由type类产生的:>>>元类(产生类的类)'''

产生类的两种方式

1.使用关键字class

'1.使用关键字class'
class Student():
    country = 'China'

    def func(self):
        pass

print(Student)  # <class '__main__.Student'>
print(Student.__dict__)

2.利用元类type

'2.利用元类type'
'''
可以通过追代码的方式找到
type(object_or_name, bases, dict)
type('类名','父类'(没有可以直接写小括号),'类的名称空间'(字典的形式))
'''
# type(类名,类的父类(没有可以直接小括号),类的名称空间)
cls = type('Myclass', (), {'name': 'jack'})
print(cls)  # <class '__main__.Myclass'>
c1 = cls()
print(c1)  # <__main__.Myclass object at 0x0000028BA9696B50>

'''
为什么要学元类?有什么用?
学习元类其实就是掌握了类的产生过程 
我们就可以在类的产生过程中高度定制化类的行为
'''

元类定制类的产生行为

思考:我们的定制化代码应该写在哪里?

推导:
  对象是如何产生的?调用类然后执行类里面的__init__方法
  类是如何产生的?推导应该是,创造类的类里面的__init__方法而这个类恰好是type元类
  得出结论:如果想定制化类的代码,一个写在元类的__init__方法

'''
推导:使用已知推导未知
# 你能够直接修改元类的代码吗?不能够直接修改元类的源码,我们是不是可以写一个子类,
来继承type类,然后在子类里面的__init__犯法中书写定制化代码,所以还需要再子类里面
执行父类的__init__方法
'''

'''定制一个所有的类必须首字母大写 否则无法产生的功能'''
# 分析:想要干预一个类的产生,必须要考虑使用元类,元类产生类
'''步骤1:自定义元类,继承type的类也称为元类'''
class MyClass(type):
    '''3.类名加括号会触发__init__初始化方法'''
    '''
    类中的__init__方法用于实例化对象
    元类中的__init__方法用于实例化类
    '''
    def __init__(self, cls_name, cls_bases, cls_dict):
    # 通过查看元类源码里的__init__(self,what,bases=None,dict=None)
        # print(cls_name)  # Zero 类名
        # print(cls_bases)  # ()  父类
        # print(cls_dict)  # 名称空间(一个大字典)

        # 定义一个类名首字母没大写无法产生的功能
        if not cls_name.istitle():
            raise Exception('类名首字母一定要大写啊!SB')
        
        super().__init__(cls_name,cls_bases,cls_dict)


'''2.定义一个子类来继承,元类不能直接继承,需要指定metaclass= MyClass'''
# 先来一个首字母大写的看看
class Zero(metaclass=MyClass):
    def __init__(self):
        print('from Zero')

Zero()
print(Zero.__dict__)  # 已经实现了,定制化,该类产生了

# 在来定义一个首字母不大写的类看看效果
class ankn(metaclass=MyClass):
    def __init__(self):
        print('from ankn')

ankn()
print(ankn.__dict__)  # 已经实现了,定制化,该类没有产生

元类进阶用法

'''
元类的__call__方法
对象()的时候会调用产生对象的类中得的__call__方法
推导:
    类名()?
    会执行 产生类的类中得__call__方法,其实就是元类type中的__call__
'''

'''
元类不单单可以控制类的产生过程,其实也可以控制对象的
对象加括号执行产生该对象类里面的__call__
类加括号执行产生改类的元类里面的__call__
'''
'''我们可以做一个实例化对象后,让所有的参数必须都采用关键字参数的形式'''
class MyClass(type):
    def __call__(self, *args, **kwargs):
        '''
        1.产生一个空对象(骨架)
        2.调用__init__给对象天津爱独有的数据(血肉)
        3.返回创建好的对象
        :param args:
        :param kwargs:
        :return:
        '''
        print('__call__')
        print(args)  # ('jack', 18)
        print(kwargs)  # {}

        if not kwargs:
            raise Exception('喂喂!给我传关键字形参啊!')
        # 返回创建好的值
        return super().__call__(*args, **kwargs)


class Zero(metaclass=MyClass):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        print('__init__')

# z = Zero('jack',18)
'''
观察一下Zero类里面的__init__方法和MyClass里面的__call方法执行顺序
从代码运行中可以得出结论:在执行类的__init__方法之前,其实已经执行了元类的__call__方法。
既然这样那么我们就可以在实例化对象之前做一些定制化
'''
# 实例化对象会立马触发元类里面的__call__,括号内的值是先给*args,**kwags的
z1 = Zero(name='tom',age=19)

'''
如果我们想要定制对象的产生过程可以操作元类里面的__call__
如果我们想要定类的产生过程可以操作元类里面的__init__
'''
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值