最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python黑魔法之metaclass詳情

 更新時(shí)間:2021年09月15日 10:15:15   作者:somenzz Python七號  
Python 有很多黑魔法,為了不分你的心,今天只講 metaclass。對于 metaclass 這種特性,有兩種極端的觀點(diǎn):下面小編將為大家詳細(xì)的介紹,剛興趣的小伙伴可以參考一下

關(guān)于Python 黑魔法 metaclass 的兩種極端觀點(diǎn):

  • 這種特性太牛逼了,是無所不能的阿拉丁神燈,必須找機(jī)會用上才能顯示自己的 Python 實(shí)力。
  • 這個(gè)特性太危險(xiǎn),會蠱惑人心去濫用,一旦打開就會釋放惡魔,讓代碼難以維護(hù)。

今天我們就來看看,metaclass 到底是阿拉丁神燈,還是潘多拉魔盒。

一、什么是 metaclass

很多書都會翻譯成 元類,僅從字面理解, meta 的確是元,本源,翻譯沒毛病。但理解時(shí),應(yīng)該把元理解為描述數(shù)據(jù)的超越數(shù)據(jù),事實(shí)上,metaclass 的 meta 起源于希臘詞匯 meta,包含兩種意思:

  • Beyond”,例如技術(shù)詞匯 metadata,意思是描述數(shù)據(jù)的超越數(shù)據(jù)。
  • Change”,例如技術(shù)詞匯 metamorphosis,意思是改變的形態(tài)。

因此可以理解為 metaclass 為描述類的超類,同時(shí)可以改變子類的形態(tài)。你可能會問了,這和元數(shù)據(jù)的定義差不多么,這種特性在編程中有什么用?

用處非常大。在沒有 metaclass 的情況下,子類繼承父類,父類是無法對子類執(zhí)行操作的,但有了 metaclass,就可以對子類進(jìn)行操作,就像裝飾器那樣可以動態(tài)定制和修改被裝飾的類,metaclass 可以動態(tài)的定制或修改繼承它的子類。

二、metaclass 能解決什么問題?

你已經(jīng)知道了 metaclass 可以像裝飾器那樣定制和修改繼承它的子類,這里就說下它能解決什么實(shí)際問題。比方說,在一個(gè)智能語音助手的大型項(xiàng)目中,我們有 1 萬個(gè)語音對話場景,每一個(gè)場景都是不同團(tuán)隊(duì)開發(fā)的。作為智能語音助手的核心團(tuán)隊(duì)成員,你不可能去了解每個(gè)子場景的實(shí)現(xiàn)細(xì)節(jié)。

在動態(tài)配置實(shí)驗(yàn)不同場景時(shí),經(jīng)常是今天要實(shí)驗(yàn)場景 A 和 B 的配置,明天實(shí)驗(yàn) B 和 C 的配置,光配置文件就有幾萬行量級,工作量不可謂不小。而應(yīng)用這樣的動態(tài)配置理念,我就可以讓引擎根據(jù)我的文本配置文件,動態(tài)加載所需要的 Python 類。

如果你還不是很清楚,那么 YAML 你應(yīng)該知道,它是一個(gè)家喻戶曉的 Python 工具,可以方便地序列化和反序列化數(shù)據(jù),YAMLObject 可以讓它的任意子類支持序列化和反序列化(serialization & deserialization)。

序列化和反序列化:

  • 序列化:當(dāng)程序運(yùn)行時(shí),所有的變量或者對象都是存儲到內(nèi)存中的,一旦程序調(diào)用完成,這些變量或者對象所占有的內(nèi)存都會被回收。而為了實(shí)現(xiàn)變量和對象持久化的存儲到磁盤中或在網(wǎng)絡(luò)上進(jìn)行傳輸,我們需要將變量或者對象轉(zhuǎn)化為二進(jìn)制流的方式。而將其轉(zhuǎn)化為二進(jìn)制流的過程就是序列化。
  • 反序列化:而反序列化就是說程序運(yùn)行的時(shí)候不能從磁盤中進(jìn)行讀取,需要將序列化的對象或者變量從磁盤中轉(zhuǎn)移到內(nèi)存中,同時(shí)也會將二進(jìn)制流轉(zhuǎn)換為原來的數(shù)據(jù)格式。我們把這一過程叫做反序列化。

現(xiàn)在你有 1 萬個(gè)不同格式的 YAML 配置文件,本來你需要寫 1 萬個(gè)類來加載這些配置文件,有了 metaclass,你只需要實(shí)現(xiàn)一個(gè) metaclass 超類,然后再實(shí)現(xiàn)一個(gè)子類繼承這個(gè) metaclass,就可以根據(jù)不同的配置文件自動拉取不同的類,這極大地提高了效率。

三、通過一個(gè)實(shí)例來理解 metaclass

請手動在 ipython 中搞代碼,看看每一步都輸出了什么,這樣可以徹底的理解類的創(chuàng)建和實(shí)例化步驟。

In[15]: class Mymeta(type):
   ...:     def __init__(self, name, bases, dic):
   ...:         super().__init__(name, bases, dic)
   ...:         print('===>Mymeta.__init__')
   ...:         print(self.__name__)
   ...:         print(dic)
   ...:         print(self.yaml_tag)
   ...: 
   ...:     def __new__(cls, *args, **kwargs):
   ...:         print('===>Mymeta.__new__')
   ...:         print(cls.__name__)
   ...:         return type.__new__(cls, *args, **kwargs)
   ...: 
   ...:     def __call__(cls, *args, **kwargs):
   ...:         print('===>Mymeta.__call__')
   ...:         obj = cls.__new__(cls)
   ...:         cls.__init__(cls, *args, **kwargs)
   ...:         return obj
   ...: 
In[16]: 
In[16]: 
In[16]: class Foo(metaclass=Mymeta):
   ...:     yaml_tag = '!Foo'
   ...: 
   ...:     def __init__(self, name):
   ...:         print('Foo.__init__')
   ...:         self.name = name
   ...: 
   ...:     def __new__(cls, *args, **kwargs):
   ...:         print('Foo.__new__')
   ...:         return object.__new__(cls)
   ...:     
===>Mymeta.__new__
Mymeta
===>Mymeta.__init__
Foo
{'__module__': '__main__', '__qualname__': 'Foo', 'yaml_tag': '!Foo', '__init__': <function Foo.__init__ at 0x0000000007EF3828>, '__new__': <function Foo.__new__ at 0x0000000007EF3558>}
!Foo

In[17]: foo = Foo('foo')
===>Mymeta.__call__
Foo.__new__
Foo.__init__

In[18]:

從上面的運(yùn)行結(jié)果可以發(fā)現(xiàn)在定義 class Foo() 定義時(shí),會依次調(diào)用 MyMeta __new__ __init__ 方法構(gòu)建 Foo 類,然后在調(diào)用 foo = Foo() 創(chuàng)建類的實(shí)例對象時(shí),才會調(diào)用 MyMeta 的 __call__ 方法來調(diào)用 Foo 類的 __new__ __init__ 方法。

把上面的例子運(yùn)行完之后就會明白很多了,正常情況下我們在父類中是不能對子類的屬性進(jìn)行操作,但是元類可以。換種方式理解元類、裝飾器、類裝飾器都可以歸為元編程。

四、Python 底層語言設(shè)計(jì)層面是如何實(shí)現(xiàn) metaclass 的?

要理解 metaclass 的底層原理,你需要深入理解 Python 類型模型。下面,將分三點(diǎn)來說明。

1、所有的 Python 的用戶定義類,都是 type 這個(gè)類的實(shí)例。

可能會讓你驚訝,事實(shí)上,類本身不過是一個(gè)名為 type 類的實(shí)例。在 Python 的類型世界里,type 這個(gè)類就是造物的上帝。這可以在代碼中驗(yàn)證:

In [2]: # Python 3和Python 2類似
   ...: class MyClass:
   ...:   pass
   ...:
   ...: instance = MyClass()
   ...:
in [3]: type(instance)
   ...:
Out[2]: __main__.MyClass
In [4]: type(MyClass)
   ...:
Out[4]: type
In [5]:


你可以看到,instance MyClass 的實(shí)例,而 MyClass 不過是“上帝” type 的實(shí)例。

2、用戶自定義類,只不過是 type 類的 __call__ 運(yùn)算符重載

當(dāng)我們定義一個(gè)類的語句結(jié)束時(shí),真正發(fā)生的情況,是 Python 調(diào)用 type 的 __call__ 運(yùn)算符。簡單來說,當(dāng)你定義一個(gè)類時(shí),寫成下面這樣時(shí):

class MyClass:
    data = 1


Python 真正執(zhí)行的是下面這段代碼:

class = type(classname, superclasses, attributedict)


這里等號右邊的 type(classname, superclasses, attributedict),就是 type 的 __call__ 運(yùn)算符重載,它會進(jìn)一步調(diào)用:

type.__new__(typeclass, classname, superclasses, attributedict)
type.__init__(class, classname, superclasses, attributedict)

當(dāng)然,這一切都可以通過代碼驗(yàn)證,比如

In [5]: class MyClass:
   ...:     data = 1
   ...:
   ...: instance = MyClass()
   ...:

In [6]: MyClass, instance
   ...:
Out[6]: (__main__.MyClass, <__main__.MyClass at 0x4ef5188>)

In [7]: instance.data
   ...:
Out[7]: 1

In [8]: MyClass = type('MyClass', (), {'data': 1})
   ...: instance = MyClass()
   ...:

In [9]: MyClass, instance
   ...:
Out[9]: (__main__.MyClass, <__main__.MyClass at 0x4f40748>)

In [10]: instance.data
    ...:
Out[10]: 1

In [11]:

由此可見,正常的 MyClass 定義,和你手工去調(diào)用 type 運(yùn)算符的結(jié)果是完全一樣的。

3、,“超越變形”正常的類

metaclass 是 type 的子類,通過替換 type 的 __call__ 運(yùn)算符重載機(jī)制,“超越變形”正常的類

其實(shí),理解了以上幾點(diǎn),我們就會明白,正是 Python 的類創(chuàng)建機(jī)制,給了 metaclass 大展身手的機(jī)會。

一旦你把一個(gè)類型 MyClass metaclass 設(shè)置成 MyMeta,MyClass 就不再由原生的 type 創(chuàng)建,而是會調(diào)用 MyMeta __call__ 運(yùn)算符重載。

class = type(classname, superclasses, attributedict) 
# 變?yōu)榱?
class = MyMeta(classname, superclasses, attributedict)

四、使用 metaclass 的風(fēng)險(xiǎn)

不過,凡事有利必有弊,尤其是 metaclass 這樣“逆天”的存在。正如你所看到的那樣,metaclass 會"扭曲變形"正常的 Python 類型模型。所以,如果使用不慎,對于整個(gè)代碼庫造成的風(fēng)險(xiǎn)是不可估量的。

換句話說,metaclass 僅僅是給小部分 Python 開發(fā)者,在開發(fā)框架層面的 Python 庫時(shí)使用的。而在應(yīng)用層,metaclass 往往不是很好的選擇。

總結(jié):

本文從 Python 類創(chuàng)建的過程,幫助你理解 metaclass 的作用。

metaclass 是黑魔法,使用得當(dāng)就是天堂,反之就是地獄。

到此這篇關(guān)于Python黑魔法之metaclass詳情的文章就介紹到這了,更多相關(guān)Python黑魔法之metaclass內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python中pre-commit的具體使用

    Python中pre-commit的具體使用

    pre-commit是Git預(yù)提交鉤子框架,通過配置文件自動執(zhí)行代碼檢查、格式化等任務(wù),確保團(tuán)隊(duì)代碼規(guī)范并提升質(zhì)量,下面就一起來了解一下
    2025-06-06
  • Django 5種類型Session使用方法解析

    Django 5種類型Session使用方法解析

    這篇文章主要介紹了Django 5種類型Session使用方法解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Pytorch搭建簡單的卷積神經(jīng)網(wǎng)絡(luò)(CNN)實(shí)現(xiàn)MNIST數(shù)據(jù)集分類任務(wù)

    Pytorch搭建簡單的卷積神經(jīng)網(wǎng)絡(luò)(CNN)實(shí)現(xiàn)MNIST數(shù)據(jù)集分類任務(wù)

    這篇文章主要介紹了Pytorch搭建簡單的卷積神經(jīng)網(wǎng)絡(luò)(CNN)實(shí)現(xiàn)MNIST數(shù)據(jù)集分類任務(wù),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • Python極簡代碼實(shí)現(xiàn)楊輝三角示例代碼

    Python極簡代碼實(shí)現(xiàn)楊輝三角示例代碼

    楊輝三角形因?yàn)槠湫问胶唵?,又有一定的使用價(jià)值,因此是入門編程題中被用的最多的,也是很好的語言實(shí)例標(biāo)的。這篇文章就給大家介紹了Python極簡代碼實(shí)現(xiàn)楊輝三角的方法,文章給出了詳細(xì)的示例代碼和解釋,對大家理解很有幫助,感興趣的朋友們下面來一起看看吧。
    2016-11-11
  • 通過Python繪制九種二次曲面的示例詳解

    通過Python繪制九種二次曲面的示例詳解

    這篇文章主要為大家詳細(xì)介紹了如何通過Python繪制九種二次曲面,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-06-06
  • 解決Pytorch修改預(yù)訓(xùn)練模型時(shí)遇到key不匹配的情況

    解決Pytorch修改預(yù)訓(xùn)練模型時(shí)遇到key不匹配的情況

    這篇文章主要介紹了解決Pytorch修改預(yù)訓(xùn)練模型時(shí)遇到key不匹配的情況,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 關(guān)于python3.9安裝wordcloud出錯(cuò)的問題及解決辦法

    關(guān)于python3.9安裝wordcloud出錯(cuò)的問題及解決辦法

    這篇文章主要介紹了關(guān)于python3.9安裝wordcloud出錯(cuò)的問題及解決辦法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • 新手必看的5個(gè)Python基礎(chǔ)語法避坑技巧(附示例代碼)

    新手必看的5個(gè)Python基礎(chǔ)語法避坑技巧(附示例代碼)

    作為剛?cè)腴T編程的新手,Python基礎(chǔ)語法看似簡單,但很容易在細(xì)節(jié)上踩坑,導(dǎo)致代碼報(bào)錯(cuò)、運(yùn)行異常,既影響效率又打擊積極性,今天整理了5個(gè)最常見的Python語法避坑點(diǎn),希望對大家有所幫助
    2026-02-02
  • PyCharm使用matplotlib報(bào)MatplotlibDeprecationWarning問題解決辦法

    PyCharm使用matplotlib報(bào)MatplotlibDeprecationWarning問題解決辦法

    這篇文章主要給大家介紹了關(guān)于PyCharm使用matplotlib報(bào)MatplotlibDeprecationWarning問題解決的相關(guān)資料,主要是 matplotlib版本過高導(dǎo)致的,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-06-06
  • python網(wǎng)絡(luò)編程:socketserver的基本使用方法實(shí)例分析

    python網(wǎng)絡(luò)編程:socketserver的基本使用方法實(shí)例分析

    這篇文章主要介紹了python網(wǎng)絡(luò)編程:socketserver的基本使用方法,結(jié)合實(shí)例形式分析了python網(wǎng)絡(luò)編程中socketserver的基本功能、使用方法及操作注意事項(xiàng),需要的朋友可以參考下
    2020-04-04

最新評論

高碑店市| 彰化县| 云阳县| 达拉特旗| 慈利县| 普兰县| 司法| 化隆| 苍山县| 翁源县| 开远市| 株洲县| 射洪县| 高密市| 桂东县| 牡丹江市| 龙岩市| 滁州市| 宜州市| 苍梧县| 汉寿县| 巴彦淖尔市| 温宿县| 将乐县| 凉城县| 札达县| 吴桥县| 永善县| 德清县| 恭城| 湘潭市| 通渭县| 容城县| 蒙自县| 大港区| 砀山县| 淮阳县| 双牌县| 威远县| 通江县| 聂拉木县|