# -*- coding: utf-8 -*- class Test: pass print(type(Test)) print(type(int)) # 结果都为,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()