|
- # -*- coding: utf-8 -*-
- class Test:
- pass
-
- print(type(Test))
- print(type(int))
-
- # 结果都为<class 'type'>,type就是内置的元类,class关键字定义的所有的类以及内置的类都是由元类type实例化产生。
-
- """
- 由于在python3中没有经典类和新式类的区别,因此python3中object是所有类的基类,那内置元类type又是什么?
- type是object类的类型,总结来说就是type是object的类型,同时,object又是type的基类,这句话看起来就有问题,
- 到底是先有type还是先有object呢?这个问题有点类似于先有鸡还是先有蛋,我们可以通过代码简单分析一下
-
- 在python3中类和类型是同一种东西,因此对象.__class__和type(对象)得到的结果是一致的,object的基类为空,
- 但是type的基类为object,但是object的类型又是type。
- """
- print(type(object))
- print(object.__class__)
-
- print(type(type))
- print(type.__class__)
-
- print(object.__bases__)
- print(type.__bases__)
-
- # python字符串
- strs = """
- global name
- global age
- name = 'py'
- age = 18
- addr = 'xx'
- """
- # 定义全局作用域中的名字和值
- globals = {
- 'a': '1',
- 'b': '2'
- }
- # 定义局部作用域中的名字和值
- locals = {
- 'x': 3,
- 'y': 4
- }
- exec(strs, globals, locals)
- print(globals['name'])
- print(locals)
-
- # 了解了exec的作用之后,就可以分析class关键字如何借助type元类产生类的步骤:
- # 1 定义类名
- class_name = 'Test'
-
- # 2 定义类的基类(父类)
- class_bases = (object,)
-
- # 3 执行类体代码拿到类的名称空间
- class_dic = {}
-
- # 4 定义类体代码(本质是字符串)
- class_body = """
- def __init__(self,name,age):
- self.name=name
- self.age=age
-
- def test(self):
- print('%s:%s' %(self.name,self.name))
- """
- # 5 将字符串转为python能识别的语法:将class_body运行时产生的名字存入class_dic中
- exec(class_body, {}, class_dic)
- # 查看类的名称空间
- print(class_dic)
- # 6 调用元类产生类
- Test = type(class_name, class_bases, class_dic)
- # 7 调用类产生对象
- t = Test('python', '12')
- t.test()
-
- # 自定义元类
- class MyMeta(type): # 自定义元类必须继承type,否则就是普通的类
-
- '''
- 早于__init__方法执行,必须返回空对象,由于该方法是调用类后第一个运行的方法,
- 此时并没有对象产生,因此该方法的第一个参数必须是类本身(MyMeta),*args, **kwargs
- 用来接收调用元类产生对象所需的参数(类名 类的基类 名称空间)
- '''
- def __new__(cls, *args, **kwargs):
- return type.__new__(cls, *args, **kwargs) # 直接调用父类type中的__new__方法
-
- '''
- 通过__init__控制类的产生,调用自定义元类与调用内置元类type的方式相同,
- 需要传入类名、类的父类们、类体代码的名称空间,__init__方法中第一个参数来自于__new__方法产生的空对象。
- '''
- def __init__(self, class_name, class_bases, class_dict):
-
- '''
- 在该方法内可以控制类的产生
- '''
- if not class_name.istitle(): # 实现类名首字母必须大写,否则抛出异常
- raise NameError('类名的首字母必须大写')
-
- if '__doc__' not in class_dict or len(class_dict['__doc__'].strip())==0: # 实现类必须有文档注释,否则抛出异常
- raise TypeError('必须有文档注释')
-
- def __call__(self, *args, **kwargs):
- print(self)
- print(args)
- print(kwargs)
- return 'test'
-
- class Test(metaclass=MyMeta):
-
- '''
- 我是文档注释
- '''
-
- def __init__(self):
- self.name = 'python'
-
- def test(self):
- print('test')
- t = Test()
|