Python元类(type()和metaclass)
1. 元類是什么
眾所周知,對(duì)象由類實(shí)例化而來(lái),類是對(duì)象的模板,而python一切皆對(duì)象,類也是對(duì)象,它由元類(type)創(chuàng)建,所以元類是類的類,是類的模板
2. 創(chuàng)建類的另一種方法
一般情況下,我們使用class關(guān)鍵字申明一個(gè)類,就像
class Demo:def __init__(self,name,age):self.name = nameself.age = agedef output(self):print("name is " + str(self.name) + " age is " + str(self.age))if __name__ == '__main__':demo = Demo("Bob",18)demo.output()python 中所有的類都是通過(guò)type創(chuàng)建的,所以當(dāng)我們使用type()函數(shù)查看類的類型時(shí)會(huì)顯式<class type>
>>> class Demo:pass>>> type(Demo) <class 'type'> >>> demo = Demo() >>> type(demo) <class '__main__.Demo'>通過(guò)類實(shí)例化出來(lái)的對(duì)象的類型是<class 類名>,這樣也更加驗(yàn)證了所有類都是由元類type實(shí)例化而來(lái)
通過(guò)type創(chuàng)建類
可以看一下type的文檔,type可以傳入三個(gè)參數(shù),object_or_name, bases, dict,當(dāng)只有一個(gè)參數(shù)是object時(shí),返回該對(duì)象的類型,就是最常使用的這種情況,當(dāng)傳入name, bases, dict參數(shù)時(shí),會(huì)返回一個(gè)類,name是類名,bases是基類元組,dict是類中屬性和方法的字典
class type(object):"""type(object_or_name, bases, dict)type(object) -> the object's typetype(name, bases, dict) -> a new type"""我們使用type重寫一下上面的Demo類
# 模擬__init__() def __init__(self,name,age):self.name = nameself.age = agedef output(self):print("name is " + str(self.name) + " age is " + str(self.age))class_name = 'Demo' class_bases = (object,) class_dict = {'__init__':__init__,'output': output, }# type(name, bases, dict) -> a new type Demo = type(class_name,class_bases,class_dict) demo = Demo('Bob',18) demo.output() # name is Bob age is 18實(shí)際上,每次用class定義類時(shí),執(zhí)行的都是type()方法
3. MetaClass
既然所有類都是由type創(chuàng)建的,那我們就可以控制類的創(chuàng)建行為,這就需要使用元類metaclass
- 元類用來(lái)創(chuàng)建類,實(shí)質(zhì)上也是一個(gè)類,繼承自type
- __new__是真正的構(gòu)造函數(shù),用來(lái)分配內(nèi)存空間__new__(cls: type, name: str, bases: Tuple[type, ...], namespace: Dict[str, Any]) -> type
在用class定義類時(shí),括號(hào)中可以指定metaclass,指定后會(huì)創(chuàng)建__metaclass__,python在創(chuàng)建類的時(shí)候,會(huì)先檢查有沒(méi)有__metaclass__,如果有,就會(huì)以此方法創(chuàng)建對(duì)象,沒(méi)有就會(huì)逐級(jí)向上查找父類中有沒(méi)有該,如果找到當(dāng)前package中還沒(méi)有找到,就會(huì)使用默認(rèn)的type創(chuàng)建(調(diào)用metaclass.__new__())
值得注意的是,如果我們?cè)谧鲱惖亩x時(shí),在class聲明處傳入關(guān)鍵字metaclass=ListMetaclass,那么如果傳入的這個(gè)metaclass有__call__函數(shù),這個(gè)__call__函數(shù)將會(huì)覆蓋掉MyList class的__new__函數(shù)。這是為什么呢?請(qǐng)大家回想一下,當(dāng)我們實(shí)例化MyList的時(shí)候,用的語(yǔ)句是L1=MyList(),而我們知道,__call__函數(shù)的作用是能讓類實(shí)例化后的對(duì)象能夠像函數(shù)一樣被調(diào)用。也就是說(shuō)MyList是ListMetaclass實(shí)例化后的對(duì)象,而MyList()調(diào)用的就是ListMetaclass的__call__函數(shù)。另外,值得一提的是,如果class聲明處,我們是讓MyList繼承ListMetaclass,那么ListMetaclass的__call__函數(shù)將不會(huì)覆蓋掉MyList的__new__函數(shù)。
元類在一般情景下很少用到,但在像ORM中還是會(huì)有應(yīng)用的,ORM(對(duì)象關(guān)系映射),ORM看這位大佬的文章談?wù)凱ython中元類Metaclass(二):ORM實(shí)踐
4. 總結(jié)
- 通過(guò)class定義的類其實(shí)是通過(guò)type()創(chuàng)建的
- type(object_or_name, bases, dict)
- 如果想要控制類的創(chuàng)建行為,需要在創(chuàng)建類時(shí)指定metaclass,一旦指定了metaclass,就會(huì)在class上添加__metaclass__,創(chuàng)建類時(shí)會(huì)找__metaclass__指向的類,并用這個(gè)類創(chuàng)建類,如果找不到,就會(huì)調(diào)用默認(rèn)的type()
參考文章
Python中的元類(metaclass)
談?wù)凱ython中元類Metaclass(一):什么是元類
Python之元類
總結(jié)
以上是生活随笔為你收集整理的Python元类(type()和metaclass)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 简单步骤Centos7安装Tomcat
- 下一篇: python字体大小设置苹果电脑_如何调