日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

Python元类(type()和metaclass)

發(fā)布時(shí)間:2023/12/20 python 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python元类(type()和metaclass) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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
def add(self, value):print('add one value')self.append(value)class ListMetaclass(type):def __new__(mcs, name, bases, namespace):namespace['add'] = addreturn type.__new__(mcs, name, bases, namespace)class MyList(list, metaclass=ListMetaclass):passli = MyList() li.add(1) print(li)

在用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)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。