day 28-1 元类
程序员文章站
2022-06-05 18:17:01
元类,元类的用途:自定义元类控制类的创建行为及类的实例化行为 ......
元类
元类的用途:自定义元类控制类的创建行为及类的实例化行为
python 中一切皆为对象。
一切接对象,对象可以怎么用呢?
1、都可以被引用,x=obj
2、都可以当作函数的参数传入
3、都可以当作函数的返回值
4、都可以当作容器类的元素,l=[func,time,obj,1]
让我们先定义一个类,然后逐步分析
class people(): def __init__(self, name, age): self.name = name self.age = age def say(self): print('%s say welcome to here' % self.name) p = people('ysg', 21) p.say() print(type(p)) # <class '__main__.people'> print(type(people)) # <class 'type'>
所有的对象都是实例化或者说调用类而得到的(调用类的过程称为类的实例化),比如对象t1是调用类oldboyteacher得到的
如果一切皆为对象,那么类 peope 本质也是一个对象,既然所有的对象都是调用类得到的,那么 peope 必然也是调用了一个类得到的,这个类称为元类
总结:产生类的类称之为元类,默认使用 class 定义的类,他们的元类是 type。
exec的用法
参数1:字符串形式的命令
参数2:全局作用域(字典形式),如果不指定默认就是用 globals()
参数3:局部作用局(字典形式),如果不指定默认就是用 locals()
例子
g = { 'x': 'ysg', 'y': '123' } l = {} exec(""" global x,m x = 'ysging' m = 'pei' z = '21' """, g, l) print(g) # {'x': 'ysging', 'y': '123'..., 'm': 'pei'} print(l) # {'z': '21'}
元类定义的两种方式
方法一:class
class people(): country = "china" def __init__(self, name, age): self.name = name self.age = age def func(self): print('%s say good' % self.name) p = people('ysg', '22') print(people) # <class '__main__.people'> print(p, p.name, p.age) # <__main__.people object at 0x0000020b0fc652e8> ysg 22
方法二:type
定义类的三要素:类名、类的基类、类的名称空间
class_name = 'people' class_bases = (object,) class_body = """ country = "china" def __init__(self, name, age): self.name = name self.age = age def func(self): print('%s say good' % self.name) """ class_dic = {} exec(class_body, globals(), class_dic) people1 = type(class_name, class_bases, class_dic) print(people1) # <class '__main__.people'> p1 = people1('ysg', '22') print(p1, p1.name, p1.age) # <__main__.people object at 0x0000020b0fc65470> ysg 22
自定义元类控制类的创建行为
实现检索类名称是否为大写,类中是否写入注释
class mymeta(type): def __init__(self, class_name, class_bases, class_dic): super(mymeta, self).__init__(class_name, class_bases, class_dic) if not class_name.istitle(): raise typeerror('类名称首字母要求大写') if '__doc__' not in class_dic or not class_dic['__doc__'].strip(): raise typeerror('新建的类必须标有注释') class people(object, metaclass=mymeta): # people = mymeta(class_name,class_bases,class_dic) ''' 使用自定义元类控制类的创建行为 ''' country = "china" def __init__(self, name, age): self.name = name self.age = age def func(self): print('%s say good' % self.name)
自定义元类控制类的实例化行为
预备知识 __call__
class foo(): pass f = foo() f() # typeerror: 'foo' object is not callable
class foo(): def __call__(self, *args, **kwargs): print(self) print(args) print(kwargs) f = foo() f(1, 2, 3, a=1, b=2, c=3) 结果: <__main__.foo object at 0x000001dbe6b7f240> (1, 2, 3) {'a': 1, 'b': 2, 'c': 3}
由以上两个例子可以看出,在调用方式实际是自动调用了 __call__ 方法
所以可以得出,在使用元类控制类的实例化行为时:
元类内部也应该有一个 __call__ 方法,会在调用 foo 时触发执行;foo(1,2,x=1) 就相当于 foo.__call__(foo,1,2,x=1)