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

Python 中 Meta Classes詳解

 更新時(shí)間:2016年02月13日 10:33:16   投稿:hebedich  
首先,在認(rèn)識(shí)metaclass之前,你需要認(rèn)識(shí)下python中的class。python中class的奇怪特性借鑒了smalltalk語(yǔ)言。大多數(shù)語(yǔ)言中,classes僅僅是用于描述怎樣創(chuàng)建一個(gè)對(duì)象的代碼端。在某種程度上說(shuō),python中的class也是這樣的。

接觸過(guò) Django 的同學(xué)都應(yīng)該十分熟悉它的 ORM 系統(tǒng)。對(duì)于 python 新手而言,這是一項(xiàng)幾乎可以被稱作“黑科技”的特性:只要你在models.py中隨便定義一個(gè)Model的子類,Django 便可以:

  1. 獲取它的字段定義,并轉(zhuǎn)換成表結(jié)構(gòu)
  2. 讀取Meta內(nèi)部類,并轉(zhuǎn)化成相應(yīng)的配置信息。對(duì)于特殊的Model(如abstract、proxy),還要進(jìn)行相應(yīng)的轉(zhuǎn)換
  3. 為沒(méi)有定義objects的Model加上一個(gè)默認(rèn)的Manager

開發(fā)之余,我也曾腦補(bǔ)過(guò)其背后的原理。曾經(jīng),我認(rèn)為是這樣的:

啟動(dòng)時(shí),遍歷models.py中的所有屬性,找到Model的子類,并對(duì)其進(jìn)行上述的修改。
當(dāng)初,我還以為自己觸碰到了真理,并曾將其應(yīng)用到實(shí)際生產(chǎn)中——為 SAE 的 KVDB 寫了一個(gè)類 ORM 系統(tǒng)。然而在實(shí)現(xiàn)的過(guò)程中,我明顯感受到了這種方法的丑陋,而且性能并不出色(因?yàn)橐闅v所有的定義模塊)。

那么事實(shí)上,Django 是怎么實(shí)現(xiàn)的呢?

自古以來(lái)我們制造東西的方法都是“自上而下”的,是用切削、分割、組合的方法來(lái)制造。然而,生命是自下而上地,自發(fā)地建造起來(lái)的,這個(gè)過(guò)程極為低廉。
——王晉康 《水星播種》


這句話揭示了生命的神奇所在:真正的生命都是由基本物質(zhì)自發(fā)構(gòu)成的,而非造物主流水線式的加工。

那么,如果 類 也有生命的話,對(duì)它自己的修飾就不應(yīng)該由調(diào)用者來(lái)完成,而應(yīng)該是自發(fā)的。

幸而,python 提供了造物主的接口——這便是 Meta Classes,或者稱為“元類”。

元類 是什么?

簡(jiǎn)單說(shuō):元類就是類的類。

首先,要有一個(gè)概念:

python 中,一切都是對(duì)象。

沒(méi)錯(cuò),一切,包括 類 本身。

既然,類 是 對(duì)象,對(duì)象 是 類的實(shí)例,那么——類 也應(yīng)該有 類 才對(duì)。

類的類:type

在 python 中,我們可以用type檢測(cè)一個(gè)對(duì)象的類,如:

print type(1) # <type 'int'>

如果對(duì)一個(gè)類操作呢?

print type(int) # <type 'type'>

class MyClass(object): pass

print type(MyClass) # <type 'type'>

print type(type) # <type 'type'>

這說(shuō)明:type其實(shí)是一個(gè)類型,所有類——包括type自己——的類都是type。

type 簡(jiǎn)介

從 官方文檔 中,我們可以知道:

和 dict 類似,type 也是一個(gè)工廠構(gòu)造函數(shù),調(diào)用其將返回 一個(gè)type類型的實(shí)例(即 類)。
type 有兩個(gè)重載版本:
+ `type(object)`,即我們最常用的版本。
+ `type(name, bases, dict)`,一個(gè)更強(qiáng)大的版本。通過(guò)指定 類名稱(`name`)、父類列表(`bases`)和 屬性字典(`dict`) 動(dòng)態(tài)合成一個(gè)類。

下面兩個(gè)語(yǔ)句等價(jià):

class Integer(int):

  name = 'my integer'

  def increase(self, num):
    return num + 1

  # -------------------

  Integer = type('Integer', (int, ), {
  'name': 'my integer',
  'increase': lambda self, num: \
          num + 1  # 很酷的寫法,不是么
  })

也就是說(shuō):類的定義過(guò)程,其實(shí)是type類型實(shí)例化的過(guò)程。

然而這和修飾一個(gè)已定義的類有什么關(guān)系呢?

當(dāng)然有啦~既然“類的定義”就是“type類型的初始化過(guò)程”,那其中必定會(huì)調(diào)用到type的構(gòu)造函數(shù)(__new__() 或 __init__())。只要我們繼承 type類 并修改其 __new__函數(shù),在這里面動(dòng)手腳就可以啦。

接下來(lái)我們將通過(guò)一個(gè)栗子感受 python 的黑魔法,不過(guò)在此之前,我們要先了解一個(gè)語(yǔ)法糖。

__metaclass__ 屬性

有沒(méi)覺(jué)得上面第二段示例有些鬼畜呢?它勒令程序員將類的成員寫成一個(gè)字典,簡(jiǎn)直是反人類。如果我們真的是要通過(guò)修改 元類 來(lái)改變 類 的行為的話,似乎就必須采用這種方法了~~簡(jiǎn)直可怕~~

好在,python 2.2 時(shí)引進(jìn)了一個(gè)語(yǔ)法糖:__metaclass__。

class Integer(int):

  __metaclass__ = IntMeta

現(xiàn)在將會(huì)等價(jià)于:

Integer = IntMeta('Integer', (int, ), {})

由此一來(lái),我們?cè)谑褂脗鹘y(tǒng)類定義的同時(shí),也可以使用元類啦。

栗子:子類凈化器

需求描述

你是一個(gè)有語(yǔ)言潔癖的開發(fā)者,平時(shí)容不得別人講一句臟話,在開發(fā)時(shí)也是如此。現(xiàn)在,你寫出了一個(gè)非常棒的框架,并馬上要將它公之于眾了。不過(guò),你的強(qiáng)迫癥又犯了:如果你的使用者在代碼中寫滿了臟話,怎么辦?豈不是玷污了自己的純潔?
假如你就是這個(gè)喪心病狂的開發(fā)者,你會(huì)怎么做?

在知道元類之前,你可能會(huì)無(wú)從下手。不過(guò),這個(gè)問(wèn)題你可以用 元類 輕松解決——只要在類定義時(shí)過(guò)濾掉不干凈的字眼就好了(百度貼吧的干活~~)。

我們的元類看起來(lái)會(huì)是這樣的:

sensitive_words_list = ['asshole', 'fuck', 'shit']

def detect_sensitive_words(string):
  '''檢測(cè)敏感詞匯'''
  words_detected = filter(lambda word: word in string.lower(), sensitive_words_list)

  if words_detected:
    raise NameError('Sensitive words {0} detected in the string "{1}".' \
      .format(
        ', '.join(map(lambda s: '"%s"' % s, words_detected)),
        string
      )
    )

class CleanerMeta(type):

  def __new__(cls, class_name, bases, attrs):
    detect_sensitive_words(class_name) # 檢查類名
    map(detect_sensitive_words, attrs.iterkeys()) # 檢查屬性名

    print "Well done! You are a polite coder!" # 如無(wú)異常,輸出祝賀消息

    return super(CleanerMeta, cls).__new__(cls, class_name, bases, attrs)
    # 重要!這行一定不能漏??!這回調(diào)用內(nèi)建的類構(gòu)造器來(lái)構(gòu)造類,否則定義好的類將會(huì)變成 None
現(xiàn)在,只需這樣定義基類:

class APIBase(object):

  __metaclass__ = CleanerMeta

  # ...
那么所有 APIBase 的派生類都會(huì)接受安全審查(奸笑~~):

class ImAGoodBoy(APIBase):

  a_polite_attribute = 1

# [Output] Well done! You are a polite coder!

class FuckMyBoss(APIBase):

  pass

# [Output] NameError: Sensitive words "fuck" detected in the string "FuckMyBoss".

class PretendToBePolite(APIBase):

  def __fuck_your_asshole(self):
    pass

# [Output] NameError: Sensitive words "asshole", "fuck" detected in the string "_PretendToBePolite__fuck_your_asshole".

看,即使像最后一個(gè)例子中的私有屬性也難逃審查,因?yàn)樗鼈儽举|(zhì)都是相同的。

甚至,你還可以對(duì)有問(wèn)題的屬性進(jìn)行偷偷的修改,比如 讓不文明的函數(shù)在調(diào)用時(shí)打出一行警告 等等,這里就不多說(shuō)了。

元類 在實(shí)際開發(fā)中的應(yīng)用

日常開發(fā)時(shí),元類 常用嗎?

當(dāng)然,Django 的 ORM 就是一個(gè)例子,大名鼎鼎的 SQLAlchemy 也用了這種黑魔法。

此外,在一些小型的庫(kù)中,也有 元類 的身影。比如 abc(奇怪的名字~~)——這是 python 的一個(gè)內(nèi)建庫(kù),用于模擬 抽象基類(Abstract Base Classes)。開發(fā)者可以使用 abc.abstractmethod 裝飾器,將 指定了 __metaclass__ = abc.ABCMeta 的類的方法定義成 抽象方法,同時(shí)這個(gè)類也成了 抽象基類,抽象基類是不可實(shí)例化的。這便實(shí)現(xiàn)了對(duì) 抽象基類 的模擬。

倘若你也有需要?jiǎng)討B(tài)修改類定義的需求,不妨也試試這種“黑魔法”。

小結(jié)

  1. 類 也是 對(duì)象,所有的類都是type的實(shí)例
  2. 元類(Meta Classes)是類的類
  3. __metaclass__ = Meta 是 Meta(name, bases, dict) 的 語(yǔ)法糖
  4. 可以通過(guò)重載元類的 __new__ 方法,修改 類定義 的行為

相關(guān)文章

  • Jupyter notebook 不自動(dòng)彈出網(wǎng)頁(yè)的解決方案

    Jupyter notebook 不自動(dòng)彈出網(wǎng)頁(yè)的解決方案

    這篇文章主要介紹了Jupyter notebook 不自動(dòng)彈出網(wǎng)頁(yè)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-05-05
  • 利用python生成照片墻的示例代碼

    利用python生成照片墻的示例代碼

    這篇文章主要介紹了利用python生成照片墻的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • Python獲取excel的數(shù)據(jù)并繪制箱型圖和直方圖的方法實(shí)例

    Python獲取excel的數(shù)據(jù)并繪制箱型圖和直方圖的方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于Python獲取excel的數(shù)據(jù)并繪制箱型圖和直方圖的相關(guān)資料,好的圖表能幫助我們深化數(shù)據(jù)的記憶點(diǎn),文中通過(guò)圖文以及代碼示例將實(shí)現(xiàn)的方法介紹的非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • python使用pandas按照行數(shù)分割表格

    python使用pandas按照行數(shù)分割表格

    本文主要介紹了python使用pandas按照行數(shù)分割表格,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Django如何利用uwsgi和nginx修改代碼自動(dòng)重啟

    Django如何利用uwsgi和nginx修改代碼自動(dòng)重啟

    這篇文章主要介紹了Django如何利用uwsgi和nginx修改代碼自動(dòng)重啟問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • Python編程快速上手——強(qiáng)口令檢測(cè)算法案例分析

    Python編程快速上手——強(qiáng)口令檢測(cè)算法案例分析

    這篇文章主要介紹了Python強(qiáng)口令檢測(cè)算法,結(jié)合實(shí)例形式分析了Python針對(duì)密碼口令強(qiáng)度檢測(cè)的相關(guān)算法實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2020-02-02
  • python 實(shí)現(xiàn)方陣的對(duì)角線遍歷示例

    python 實(shí)現(xiàn)方陣的對(duì)角線遍歷示例

    今天小編就為大家分享一篇python 實(shí)現(xiàn)方陣的對(duì)角線遍歷示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-11-11
  • 微信跳一跳輔助python代碼實(shí)現(xiàn)

    微信跳一跳輔助python代碼實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了微信跳一跳輔助的python代碼實(shí)現(xiàn)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • 30道python自動(dòng)化測(cè)試面試題與答案匯總

    30道python自動(dòng)化測(cè)試面試題與答案匯總

    對(duì)于機(jī)器學(xué)習(xí)算法工程師而言,Python是不可或缺的語(yǔ)言,它的優(yōu)美與簡(jiǎn)潔令人無(wú)法自拔,下面這篇文章主要給大家介紹了關(guān)于30道python自動(dòng)化測(cè)試面試題與答案匯總的相關(guān)資料,需要的朋友可以參考下
    2023-03-03
  • python使用Turtle庫(kù)繪制動(dòng)態(tài)鐘表

    python使用Turtle庫(kù)繪制動(dòng)態(tài)鐘表

    這篇文章主要為大家詳細(xì)介紹了python使用Turtle庫(kù)繪制動(dòng)態(tài)鐘表,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-11-11

最新評(píng)論

十堰市| 塔城市| 顺昌县| 山西省| 邹平县| 若羌县| 万州区| 大连市| 庄浪县| 永寿县| 洛扎县| 辽中县| 凯里市| 孟津县| 海丰县| 甘德县| 晋中市| 安陆市| 大宁县| 海林市| 宾阳县| 长汀县| 青田县| 招远市| 夏津县| 泗阳县| 海盐县| 泰宁县| 宜兴市| 台中县| 大埔县| 新竹县| 潍坊市| 渝中区| 聊城市| 若尔盖县| 怀集县| 甘洛县| 山西省| 芒康县| 汾西县|