马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
目录
面向对象之元类
一、什么是元类
- 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)) # <class 'str'>
- # print(type(l1)) # <class 'list'>
- # print(type(d1)) # <class 'dict'>
- # print(type(t1)) # <class 'tuple'>
- """推导步骤2:其实type方法是用来查看产生对象的类名"""
- # class Student:
- # pass
- # obj = Student()
- # print(type(obj)) # <class '__main__.Student'>
- """推导步骤3:python中一切皆对象 我们好奇type查看类名显示的是什么"""
- class Student:
- pass
- obj = Student()
- print(type(obj)) # <class '__main__.Student'>
- print(type(Student)) # <class 'type'>
- class A:pass
- class B:pass
- print(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 obj
- class Student(metaclass=MyMetaClass):
- def __init__(self, name):
- self.name = name
- obj = Student('jason')
- print(obj.name)
- """
- __new__可以产生空对象
- """
复制代码 |