目录

  • 面向对象之元类
    • 一、什么是元类
    • 二、元类推导流程
    • 三、创建类的方式
      • 方式一:
      • 方式二:
    • 四、元类定制类的产生行为
    • 五、元类定制对象的产生行为
    • 六、元类之双下new

面向对象之元类一、什么是元类

  • Python中一切皆为对象,对象是有类实例化生成;
  • 类也是对象(类对象),生成类对象的类可称之为元类;
  • 所以,元类就是来创建类对象的,可称之为类工厂;
  • type是python内建元类,type是最上层的元类,也可称为一切类对象的元类

二、元类推导流程

"""推导步骤1:如何查看数据的数据类型"""# s1 = 'hello world'  # str()# l1 = [11, 22, 33, 44]  # list()# d1 = {'name': 'jason', 'pwd': 123}  # dict()# t1 = (11, 22, 33, 44)  # tuple()# print(type(s1))  # # print(type(l1))  # # print(type(d1))  # # print(type(t1))  # """推导步骤2:其实type方法是用来查看产生对象的类名"""# class Student:#     pass# obj = Student()# print(type(obj))  # """推导步骤3:python中一切皆对象 我们好奇type查看类名显示的是什么"""class Student:    passobj = Student()print(type(obj))  # print(type(Student))  # class A:passclass B:passprint(type(A), type(B))"""结论:我们定义的类其实都是由type类产生的>>>:元类(产生类的类)"""

三、创建类的方式方式一:

创建方法:

​直接使用class关键字创建

class Foo:    school_name = 'kangkang    def func1(self):        pass    print(Teacher)    print(Teacher.__dict__)

方式二:

创建方法:

​使用元类type

​type(类名, 类的父类, 类的名称空间)

cls = type('Student', (object,), {'name':'jason'})print(cls)print(cls.__dict__)"""1.手动写键值对    针对绑定方法不好定义2.内置方法exec    能够运行字符串类型的代码并产生名称空间"""

四、元类定制类的产生行为

​通过上述推导,我们得出了我们所创建的类,其实就是type帮我们所生成的,那么我们是否可以通过继承type(元类)的方式,来研究type底层代码原理,来改修,新增条件,来定制类的生成

例如:

​生成类时,类名的首字母必须大写,否则报错

推导流程:

"""推导1、对象是由类名加括号产生的  __init__2、类是由元类加括号产生的__init__3、查看type底层源码,找到__init__        __init__(cls, what, bases=None, dict=None)        cls:元类本身        what:需要产生的类名        bases:产生类的父类        dict:类体名称空间4、通过上述我们就可以发现what可以控制类名的产生"""# 1、首先生成一个类,继承元类(type)     class MyMetaClass(type):        pass    # 2、在类中,创建def __init__(self, what, bases=None, dict=None):# 3、对限制what产生类名的条件class MyMetaClass(type):            def __init__(self, what, bases=None, dict=None):                # 设置条件,未满足时,主动抛出异常并提示        if not what.istitle():            raise TypeError('类的首字母要大写')                    # 条件满足后调用父类进行产生        super().__init__(what, bases, dict)# 4、指定类的元类:利用关键字metaclass指定类的元类class myclass(metaclass=MyMetaClass):    desc = '元类其实很有趣 就是有点绕'class Student(metaclass=MyMetaClass):    info = '我是学生 我很听话'print(Student)print(Student.__dict__)# 5、这个时候我们在生成MyMetaClass的子类时,就必须要遵循它的条件,否则将会报错

五、元类定制对象的产生行为

要求:

​生成的对象必须使用关键字进行传参,否则将无法生成对象

推导流程:

'''推导:1、我们在上述学习了类的魔法方法,发现:2、对象加括号会执行产生该对象类里的__call__3、类加括号会执行产生该类的类里的__call__4、观察__call__(self, *args, **kwargs):self: 调用者本身*args:接收位置实参**kwargs:接收关键字实参5、得出结论,我们需要对args进行约束就可达到条件'''class MyMetaClass(type):    def __call__(self, *args, **kwargs):                # 1.产生一个空对象(骨架)        # 2.调用__init__给对象添加独有的数据(血肉)        # 3.返回创建好的对象        # print(args)  # ('jason', 18, 'male')        # print(kwargs)  # {}           # 设置条件        if args:        # 当条件未满足时,主动抛出异常,并提升            raise TypeError("需要进行关键字传参")                    # 条件满足后执行,使用super,重新调用父类        return super().__call__(*args, **kwargs)    class Student(metaclass=MyMetaClass):    def __init__(self, name, age, gender):        # print('__init__')        self.name = name        self.age = age        self.gender = gender# obj = Student('jason', 18, 'male')obj = Student(name='jason',age= 18,gender= 'male')print(obj.__dict__)

六、元类之双下new

​当我们在使用类产生对象时,类体代码种名字产生的顺序是:

​__ call __ >>>: __ new __ >>>:__ init __

​双下call将类名传给双下new,然后new将对象的名字传给双下init而后产生类名

​得出结论:对象是由new进行产生的

class MyMetaClass(type):    def __call__(self, *args, **kwargs):                # 1.产生一个空对象(骨架)        obj = self.__new__(self)                # 2.调用__init__给对象添加独有的数据(血肉)        self.__init__(obj,*args, **kwargs)                # 3.返回创建好的对象        return objclass Student(metaclass=MyMetaClass):    def __init__(self, name):        self.name = nameobj = Student('jason')print(obj.name)"""__new__可以产生空对象"""