Python 中最黑魔法、最难懂的概念
最近在看一個開源框架的源碼,其中大量使用了 metaclass 方法。這個概念非常抽象,本文我就以一個有趣實例,用更簡潔和通暢的方式來理解它。
元類 ( metaclass )應該是 Python 中最黑魔法、最難懂的概念之一,它提供了創造新類型的能力,為程序設計帶來更多可能性。不少功能強大的開發框架,內部實現離不開 metaclass 的魔法。
Class
面向對象編程最重要的概念就是類(Class)和實例(Instance),我們先來創建一個 Lxs 的類,它有兩個基本功 sing 和 dance ,lxs 是這個類的實例:
class?Lxs(object):?def?__init__(self,?name,?duration):self.name?=?nameself.duration?=?durationprint('%s?practiced?%s?years'?%?(self.name,?self.duration))def?sing(self):print('%s?good?at?singing'?%?self.name)def?dance(self):print('%s?good?at?dancing'?%?self.name)lxs?=?Lxs('laohu',1.5) lxs.sing() lxs.dance()練習時常1年半的老胡擅長唱和跳
恩,針不戳!
再來用__class__屬性或type()看看 Lxs 和 lxs 分別是誰創建的
print(lxs.__class__) print(Lxs.__class__)lxs 是 Lxs 的實例,它創建自 Lxs ,這很容易理解。
我們 Lxs 類是 type 創建的?
<class?'__main__.Lxs'> <class?'type'>一切對象都來自 type
先說結論:type 可以動態創建 類(class) ,對象是類(class)的實例,類(class)也是對象,是 type 的實例。type 為對象的頂點,所有對象都創建自 type 。
當使用 type 創建 class 時,其用法如下:
class?=?type(classname,?superclasses,?attributedict) ''' classname:類名 superclasses:類的繼承關系,用元組表示 attributedict:表示各種屬性、方法,用字典表示 '''繼續上例,先定義__init__,sing 和 dance ,然后用 type 可以創建和上面完全一樣的類:
Lxs?=?type('Lxs',?(object,),?dict(?__init__=?__init__,sing=sing,dance=dance)) lxs?=?Lxs('laohu',1) lxs.sing() print(lxs.__class__) print(Lxs.__class__)這里不得不提一下__call__這個屬性
此方法會在實例作為一個函數被“調用”時被調用
這里等號右邊的type(classname, superclasses, attributedict),就是 type 的__call__運算符重載,它會進一步調用:
總結一下:type 實際上是 Python 創建所有 class 的 metaclass。
metaclass
除了使用type()動態創建類以外,要控制類的創建行為,還可以使用metaclass。
先定義metaclass,就可以創建類,最后創建實例。
一句話:metaclass 是 type 的子類,是類的模板
metaclass 的主要目的是在 class 被創建的時候對生成的 class 進行自動的動態修改。
舉個例子:像老胡就只會 sing 和 dance,有人還會rap,有人會說相聲,我們定義很多的 class ,有一天,一個男人橫空出世,他會打籃球!然后,所有的練習生也都學會了籃球,這可怎么修改?
metaclass 就可以施展魔法了
class?LxsMetaclass(type):def?__new__(cls,?cls_name,?bases,?attrs):def?basketball(self):print('%s?good?at?basketball'?%?self.name)attrs['basketball']?=?basketballreturn?super(LxsMetaclass,?cls).__new__(cls,?cls_name,?bases,?attrs)它指示Python解釋器在創建 LxsMetaclass 時,要通過LxsMetaclass.new()來創建,在此,我們可以修改類的定義,比如,加上新的方法basketball(),然后,返回修改后的定義。
我們用 LxsMetaclass 這個模板創建類:
class?Cxk(object,?metaclass=LxsMetaclass):def?__init__(self,?name,?duration):self.name?=?nameself.duration?=?durationprint('%s?practiced?%s?years'?%?(self.name,?self.duration))def?sing(self):print('%s?good?at?singing'?%?self.name)def?dance(self):print('%s?good?at??dancing'?%?self.name)def?rap(self):print('%s?good?at??rap'?%?self.name)cxk?=?Cxk('cxk',2.5) cxk.basketball()運行結果如下,秀?
cxk?practiced?2.5?years cxk?good?at?basketball不過metaclass的作用肯定不限于此,舉個例子,也算是個思考題,大家品一品。
比如 laohu 化身 xck 的粉絲,打著學籃球的幌子學 sing、dance和rap ?:
class?Funs(Cxk):def?basketball(self):print('%s?good?at??singing&dancing&rap'?%?self.name)fans?=?Funs('laohu',0.5) fans.basketball()運行結果會是什么呢?
laohu?practiced?0.5?years laohu?good?at?basketballlaohu 真的就只學會了籃球。。。
這是為何呢?且聽下回分解。
兄弟們,來個三連可好?轉發,在看,點贊
推薦閱讀
Pandas處理數據太慢,來試試Polars吧!
懶人必備!只需一行代碼,就能導入所有的Python庫
絕!關于pip的15個使用小技巧
介紹10個常用的Python內置函數,99.99%的人都在用!
可能是全網最完整的 Python 操作 Excel庫總結!
總結
以上是生活随笔為你收集整理的Python 中最黑魔法、最难懂的概念的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 告别加班:一个让你不再重复工作的技能
- 下一篇: Bokeh,一个超强交互式Python可