Python元類(type()和metaclass)

1. 元類是什么

眾所周知,對象由類實例化而來,類是對象的模板,而python一切皆對象,類也是對象,它由元類(type)創建,所以元類是類的類,是類的模板

2. 創建類的另一種方法

一般情況下,我們使用class關鍵字申明一個類,就像

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 中所有的類都是通過type創建的,所以當我們使用type()函數查看類的類型時會顯式<class type>

>>> class Demo:pass>>> type(Demo)
<class 'type'>
>>> demo = Demo()
>>> type(demo)
<class '__main__.Demo'>

通過類實例化出來的對象的類型是<class 類名>,這樣也更加驗證了所有類都是由元類type實例化而來

通過type創建類

可以看一下type的文檔,type可以傳入三個參數,object_or_name, bases, dict,當只有一個參數是object時,返回該對象的類型,就是最常使用的這種情況,當傳入name, bases, dict參數時,會返回一個類,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

實際上,每次用class定義類時,執行的都是type()方法

3. MetaClass

既然所有類都是由type創建的,那我們就可以控制類的創建行為,這就需要使用元類metaclass

  • 元類用來創建類,實質上也是一個類,繼承自type
  • __new__是真正的構造函數,用來分配內存空間__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定義類時,括號中可以指定metaclass,指定后會創建__metaclass__,python在創建類的時候,會先檢查有沒有__metaclass__,如果有,就會以此方法創建對象,沒有就會逐級向上查找父類中有沒有該,如果找到當前package中還沒有找到,就會使用默認的type創建(調用metaclass.__new__())

值得注意的是,如果我們在做類的定義時,在class聲明處傳入關鍵字metaclass=ListMetaclass,那么如果傳入的這個metaclass有__call__函數,這個__call__函數將會覆蓋掉MyList class的__new__函數。這是為什么呢?請大家回想一下,當我們實例化MyList的時候,用的語句是L1=MyList(),而我們知道,__call__函數的作用是能讓類實例化后的對象能夠像函數一樣被調用。也就是說MyList是ListMetaclass實例化后的對象,而MyList()調用的就是ListMetaclass的__call__函數。另外,值得一提的是,如果class聲明處,我們是讓MyList繼承ListMetaclass,那么ListMetaclass的__call__函數將不會覆蓋掉MyList的__new__函數。

元類在一般情景下很少用到,但在像ORM中還是會有應用的,ORM(對象關系映射),ORM看這位大佬的文章談談Python中元類Metaclass(二):ORM實踐

4. 總結

  • 通過class定義的類其實是通過type()創建的
  • type(object_or_name, bases, dict)
  • 如果想要控制類的創建行為,需要在創建類時指定metaclass,一旦指定了metaclass,就會在class上添加__metaclass__,創建類時會找__metaclass__指向的類,并用這個類創建類,如果找不到,就會調用默認的type()

參考文章

Python中的元類(metaclass)
談談Python中元類Metaclass(一):什么是元類
Python之元類

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/457612.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/457612.shtml
英文地址,請注明出處:http://en.pswp.cn/news/457612.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

word文檔打印 自動編碼_辦公室文件打印有哪些技巧 辦公室文件打印技巧介紹【圖文】...

辦公室文件打印實用技巧三則一. 打印文件直接裝訂——逆序打印相信使用Word打印過長篇文檔的朋友一定都清楚&#xff0c;打印完成后的裝訂一直是個麻煩事兒&#xff0c;因為文件由打印機打出時&#xff0c;第一頁肯定會在最下面&#xff0c;裝訂之前總要費時費力的把紙張按順序…

Strategy 策略模式

意圖 定義一系列的算法,把它們一個個封裝起來, 并且使它們可相互替換。本模式使得算法可獨立于使用它的客戶而變化。 動機 策略模式為了適應不同的需求&#xff0c;只把變化點封裝了&#xff0c;這個變化點就是實現不同需求的算法&#xff0c;但是&#xff0c;用戶需要知道各種…

python 消息中間件_消息隊列中間件 RabbitMQ 詳細介紹——安裝與基本應用(Python)...

RabbitMQ 是當前最流行的消息中間件(Message Broker)之一&#xff0c;支持多種消息協議(如 AMQP、MQTT)。同時它也是一個輕量級的非常易于部署的開源軟件&#xff0c;可以運行在當前大多數操作系統及云端環境中&#xff0c;也能夠部署在分布式的集群環境里以達到高可用、可伸縮…

用 Flask 來寫個輕博客 (1) — 創建項目

目錄 目錄前言擴展閱讀部署開發環境創建 Github 項目前言 一步一步的實現一個 Flask 輕博客項目啟動&#xff0c;最新的代碼會上傳到 Github。 擴展閱讀 歡迎使用 Flask — virtualenv 部署開發環境 連接 GitHubhostnamectl set-hostname flask-dev # 設置 hostname ssh-keyg…

python靜態方法,類方法,屬性方法,實例方法

DAY 3. 靜態方法&#xff0c;類方法&#xff0c;屬性方法&#xff0c;實例方法 有四種方法&#xff0c;實例方法&#xff0c;類方法&#xff0c;靜態方法&#xff0c;屬性方法 實例方法 實例方法的第一個參數是self&#xff0c;他會指向類的實例化對象&#xff0c;只能被對象…

ubuntu 軟件包降級

ubuntu 軟件包降級 sudo aptitude install libssl-dev 1. 是否接受該解決方案&#xff1f; [Y/n/?] n 2. 是否接受該解決方案&#xff1f; [Y/n/?] y 3. 您要繼續嗎&#xff1f; [Y/n/?] ysudo aptitude install libcairo21.4.10-1ubuntu4 # 強制降級 sudo aptitude forbid…

java后期發展方向_Java程序員的4個職業發展方向,該如何把握黃金5年?

在Java程序界流行著一種默認的說法叫“黃金5年”&#xff0c;意思是說&#xff0c;一個Java程序員從入職的時候算起&#xff0c;前五年我選擇直接影響著整個職業生涯的發展方向和薪資走向。而這5年&#xff0c;也決定了一個程序員能否成為職業大牛的可能。那么&#xff0c;在這…

python 類變量(屬性)和實例變量(屬性

DAY 4. 類變量&#xff08;屬性&#xff09;和實例變量&#xff08;屬性&#xff09; 類變量&#xff1a;在所有類的實例之間都可以共享的變量&#xff0c;類變量在所有對象間只保留一份 在類體中定義類的所有實例對象都可以訪問類變量類變量只能由類修改&#xff0c;實例對象…

MySQL 關聯表批量修改(數據同步)

update table1 t1 ,table2 t2 set t1.field1 t2.field2 where t1.id t2.id 轉載于:https://www.cnblogs.com/52php/p/5677908.html

sourcetree不好做到的一些git操作

2019獨角獸企業重金招聘Python工程師標準>>> 日常中我們有很多操作通過sourcetree就可以實現界面化操作&#xff0c;但是有一些場景不好去實現&#xff0c;這里總結下&#xff1a; 場景1&#xff1a;我們有個A分支&#xff0c;需要跟master分支合并等待上線&#xf…

vue大括號里接受一個函數_vue源碼探究(第四彈)

vue源碼探究&#xff08;第四彈&#xff09;結束了上一part的數據代理&#xff0c;這一部分主要講講vue的模板解析&#xff0c;感覺這個有點難理解&#xff0c;而且內容有點多&#xff0c;hhh。模板解析廢話不多說&#xff0c;先從簡單的入手。按照之前的套路&#xff0c;先舉一…

類級別的分裝 ---四種訪問級別

privateprivate成員為類的私有性質&#xff0c;僅有類本身和友元可以訪問&#xff1b;protected和private類似&#xff0c;區別于protected可以被該類所有派生類訪問&#xff1b;publicpublic的成員可以被外界的所有客戶代碼直接訪問published和public的區別僅在于published的成…

python自省與反射

DAY 5. python自省 這是很久之前寫的&#xff0c;當時對自省和反射的概念沒理解&#xff0c;學習Java以后多了一點理解&#xff0c;自省是獲取對象的能力&#xff0c;反射是操縱對象的能力&#xff0c;python中使用getattr()和setattr()實現反射&#xff0c;而其他的則是自省&…

vb.net 窗體接收鍵盤事件_(十五)C#WinFrom自定義控件系列-鍵盤(二)

前提入行已經7,8年了&#xff0c;一直想做一套漂亮點的自定義控件&#xff0c;于是就有了本系列文章。本系列文章將講解各種控件的開發及思路&#xff0c;歡迎各位批評指正。此系列控件開發教程將全部在原生控件基礎上進行重繪開發&#xff0c;目標的扁平化、漂亮、支持觸屏。如…

centos下cmake安裝

步驟一、安裝gcc等必備程序包&#xff08;已安裝則略過此步&#xff0c;用gcc -v檢測&#xff09; yum install -y gcc gcc-c make automake 步驟二、安裝wget &#xff08;已安裝則略過此步&#xff09; yum install -y wget 步驟三、獲取CMake源碼包 wget http://www.cmake.…

python 生成式,迭代器,生成器

DAY 6. 生成式,迭代器&#xff0c;生成器 6.1 生成式 6.1.1 列表生成式 list [index for index in range(10)]6.1.2 字典生成式 dict {zhangsan: 10,lisi: 12,wangwu: 18 } # 實現鍵值互換 dict {k:v for v,k in dict.items() if k > 12}6.1.3 集合生成式 # 100以內…

shell MAC 地址 校驗

/**************************************************************************************** shell MAC 地址 校驗* 說明&#xff1a;* 要對MAC地址進行校驗&#xff0c;記錄一下正則表達式寫法&#xff0c;有些方法在PC上驗證是可行的&…

移動端Web開發如何處理橫豎屏

<!Doctype html> <html> <head> <meta charset"utf-8"> <meta id"viewport" name"viewport" content"widthdevice-width,initial-scale1.0;"> <title>橫豎屏切換檢測</title> <style ty…

恩智浦智能車大賽2020_內蒙古科技大學第九屆智能車大賽校內公開賽總決賽

為了激發學生的創新意識&#xff0c;提高學生的動手能力&#xff0c;培養團隊合作意識&#xff0c;秉承“實踐源于真知&#xff0c;創新放飛夢想”的思想。2020年12月6日&#xff0c;內蒙古科技大學第九屆智能車大賽總決賽如約而至。本次大賽有來自各院系的223支隊伍報名參加了…

python格式化字符串的三種方法(%,format,f-string)

DAY 7. 格式化字符串 到目前為止&#xff0c;我所知道的&#xff0c;python格式化字符串有三種方法&#xff0c;第一是早期就有的%&#xff0c;其次是2.5之后的format(),還有就是3.6添加的f字符串調試 7.1 %格式化字符串 %格式化字符串是python最早的&#xff0c;也是能兼容…