Python 中最黑魔法、最難懂的概念

↑↑↑點擊上方藍字,回覆資料,10個G的驚喜

大家好,我是老胡

最近在看一個開源框架的源碼,其中大量使用了 metaclass 方法這個概念非常抽象,本文我就以一個有趣實用更簡潔和通暢的方式來理解它。

元類 ( metaclass )應該是 Python 中最黑魔法、最難懂的概念之一,它提供了創造新類型的能力,爲程序設計帶來更多可能性。不少功能強大的開發框架,內部實現離不開 metaclass 的魔法。

Class

面向對象編程最重要的概念就是類(Class)和實例(Instance),我們先來創建一個 Lxs 的類,它有兩個基本功 sing 和 dance ,lxs 是這個類的實例:

class Lxs(object): 
    def __init__(self, name, duration):
        self.name = name
        self.duration = duration
        print('%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年半的老胡擅長唱和跳
恩,針不戳!

laohu practiced 1.5 years
laohu good at singing
laohu good at dancing

再來用__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.__new__(typeclass, classname, superclasses, attributedict)
type.__init__(class, classname, superclasses, attributedict)
# 這一部分我們以後有空再細品

總結一下: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'] = basketball
        return 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 = name
        self.duration = duration
        print('%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 basketball

laohu 真的就只學會了籃球。。。

這是爲何呢?且聽下回分解。

兄弟們,來個三連可好?轉發,在看,點贊


    
    
    

推薦閱讀

(點擊標題可跳轉閱讀)

論機器學習領域的內卷

機器學習博士自救指南

機器學習入門指南(2021版)

機器學習必知必會的 6 種神經網絡類型

你見過的最全面的Python重點知識彙總

100天搞定機器學習:寫YAML配置文件

100天搞定機器學習:模型訓練好了,然後呢?

老鐵,三連支持一下,好嗎?↓↓↓

本文分享自微信公衆號 - 機器學習算法與Python實戰(tjxj666)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章