Python学习笔记八 面向对象高级编程(二)元类
参考教程:廖雪峰官网https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000
在廖老师的学习网站里“使用元类”这部分还是把我给看晕了...网上搜到一篇感觉讲的相对易懂一些,贴出链接:两句话掌握 Python 最难知识点——元类——以此文作为这篇笔记的源本。
“道生一,一生二,二生三,三生万物”
1、在Python世界中,“type”即为道,即是生出各种类、对象、变量等等一切的源头。
2、一——即是metaclass(元类,也叫类生成器)
3、二——即是各种常规的类(class)
4、三——即是实例(instance)
5、万物——即是实例的各种属性和方法
#创建一个Student类,这个类即为“二” class Student(): def printinfo(self): print("It is a instance of Student!") #创建Student的实例s,即为“二生三” s=Student() #使用实例的属性、方法,即为“三生万物” s.printinfo()
这段代码提现从二到万物的过程,那么对于Student类这个“二”从何而来呢?
我们看到的定义类的class Student()...这些代码,实际上如下:
def fn(self): print("It is a instance of Student!") Student=type('Student',(object,),dict(printinfo=fn))
注意到这里,Student类是通过type()方法生成的,其中有三个参数,分别为设置类的名字,使用一个元组明确该类的父类,使用一个字典给出这个类的方法。
type是“道”,可以先通过type生成元类,再由元类生成各种类。
“元类”
一般来说,元类都被命名为后缀Metaclass。
先看一个定义元类的例子:假设需要一个可以自动打招呼的元类,它里面的类方法有时需要say_Hello,有时需要say_Hi,有时又需要say_Sayolala,有时需要say_Nihao。
class SayMetaclass(type): #注意到元类均继承自type def __new__(cls,name,bases,attrs): attrs['say_'+name]=lambda self,value,saying=name:print(saying+','+value+'!') return type.__new__(cls,name,bases,attrs)
注意:
1、元类都是由"type"衍生出来的,所以父类必须传入type。
2、元类的操作都是通过__new__()完成,第一个参数是将创建的类的对象(是否基本类似于self?),后面三个参数分别为:类名、父类、属性/方法。
具体看这个代码:
attrs['say_'+name]=lambda self,value,saying=name:print(saying+','+value+'!')
这里是给每个类定义一个”'say_'+类名”的属性,具体在这里是一个方法,通过lambda定义的方法,这个方法有三个参数,第一个self,是因为是类的方法,所以必须第一个为self,第二个是常规的位置参数value,需要使用者自己传入,第三个是一个默认参数,默认为类名。
通过这个元类继续生出各个类:
class SayMetaclass(type): #注意到元类均继承自type def __new__(cls,name,bases,attrs): attrs['say_'+name]=lambda self,value,saying=name:print(saying+','+value+'!') return type.__new__(cls,name,bases,attrs) #通过SayMetaclass创建一个Hello类 #注意用法,参数除了第一个父类外,必须使用metaclass=标明该类使用的元类 #因为这里类名是Hello #所以这个Hello类拥有一个“say_Hello”的属性 #而这个属性又是一个方法,即等效于下面代码的方法: ''' def say_Hello(self,value,saying='Hello'): print(saying+','+value+'!') ''' class Hello(object,metaclass=SayMetaclass): pass Hello().say_Hello('World') #基于元类继续创建新的类 class Nihao(object,metaclass=SayMetaclass): pass Nihao().say_Nihao('China') Nihao().say_Nihao('China',saying='Very Great') #基于元类继续创建新的类 class Sayolala(object,metaclass=SayMetaclass): pass Sayolala().say_Sayolala('Japan')
输出如下:
Hello,World!
Nihao,China!
Very Great,China!
Sayolala,Japan!