欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python探索之Metaclass初步了解

 更新時(shí)間:2017年10月28日 10:17:47   作者:西北那個(gè)峰  
本文先簡(jiǎn)單介紹了Python中的類,然后是主要內(nèi)容,涉及Metaclass的相關(guān)內(nèi)容,還是不錯(cuò)的,這里分享給大家,供需要的朋友參考。

先以一個(gè)大牛的一段關(guān)于Python Metapgramming的著名的話來(lái)做開(kāi)頭:

Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don't (the people who actually need them know with certainty that they need them, and don't need an explanation about why). – Tim Peters

翻譯一下:Metaclasses是99%的用戶都無(wú)需費(fèi)神的黑科技。如果你還在糾結(jié)你是不是需要它的話,答案是NO (真正需要的人根本不需要解釋) – Tim Peters

這是什么鬼話?道可道,非常道嗎?

Meta?

好,裝B已畢。這確實(shí)是一個(gè)冷僻的,不常用的話題。一篇短文肯定講不完。 所以叫做初步了解。

python中的類

首先這里討論的python類,都基于繼承于object的新式類進(jìn)行討論。

首先在python中,所有東西都是對(duì)象。這句話非常重要要理解元類我要重新來(lái)理解一下python中的類

class Trick(object):
  pass

當(dāng)python在執(zhí)行帶class語(yǔ)句的時(shí)候,會(huì)初始化一個(gè)類對(duì)象放在內(nèi)存里面。例如這里會(huì)初始化一個(gè)Trick對(duì)象

這個(gè)對(duì)象(類)自身?yè)碛袆?chuàng)建對(duì)象(通常我們說(shuō)的實(shí)例,但是在python中還是對(duì)象)的能力。

為了方便后續(xù)理解,我們可以先嘗試一下在新式類中最古老厲害的關(guān)鍵字type。

input:
class Trick(object):
pass
print type('123')
print type(123)
print type(Trick())
output:
<type 'str'>
<type 'int'>
<class '__main__.Trick'>

可以看到能得到我們平時(shí)使用的 str, int, 以及我們初始化的一個(gè)實(shí)例對(duì)象Trick()

但是下面的方法你可能沒(méi)有見(jiàn)過(guò),type同樣可以用來(lái)動(dòng)態(tài)創(chuàng)建一個(gè)類

type(類名, 父類的元組(針對(duì)繼承的情況,可以為空),包含屬性的字典(名稱和值))

英文meta這個(gè)詞其實(shí)是從希臘語(yǔ)里面借來(lái)的。wikipedia上的解釋是:

indicate a concept which is an abstraction behind another concept, used to complete or add to the latter

不看還好,其實(shí)看了更暈。好在后面的解釋有一句“更高一層的抽象”,可以幫助理解。 其實(shí)我們可以這樣理解。meta的意思就是“關(guān)于什么的什么”:比如metadata可以理解為“關(guān)于數(shù)據(jù)的數(shù)據(jù)”,metaprogramming可以理解為“關(guān)于編程的編程”。這就和“更高一層的抽象” 比較契合了。同時(shí)又隱隱和編程中的另一個(gè)永恒主題-recursion聯(lián)系在了一起。

另外,meta這個(gè)詞天朝這邊翻譯成“元”,海峽對(duì)岸翻譯成“后設(shè)”。其實(shí)我都不大理解從何而來(lái)。

元類一般用于創(chuàng)建類。在執(zhí)行類定義時(shí),解釋器必須要知道這個(gè)類的正確的元類。解釋器會(huì)先尋找類屬性__metaclass__,如果此屬性存在,就將這個(gè)屬性賦值給此類作為它的元類。如果此屬性沒(méi)有定義,它會(huì)向上查找父類中的__metaclass__.如果還沒(méi)有發(fā)現(xiàn)__metaclass__屬性,解釋器會(huì)檢查名字為_(kāi)_metaclass__的全局變量,如果它存在,就使用它作為元類。否則, 這個(gè)類就是一個(gè)傳統(tǒng)類,并用 types.ClassType 作為此類的元類。

在執(zhí)行類定義的時(shí)候,將檢查此類正確的(一般是默認(rèn)的)元類,元類(通常)傳遞三個(gè)參數(shù)(到構(gòu)造器): 類名,從基類繼承數(shù)據(jù)的元組,和(類的)屬性字典。

實(shí)例

聚焦到我們今天的主題,metaprogramming就是編寫用來(lái)生成代碼的代碼。

假設(shè)我們寫了一個(gè)NB的函數(shù),用來(lái)計(jì)算一個(gè)任意復(fù)雜的算數(shù)表達(dá)式的值:

像1+2, 3*6+10, 什么的都可以交給它去計(jì)算。這樣的函數(shù)的算法不是我們的主題,所以我們請(qǐng)出python自帶的大招eval(),一行就可以搞定了:

def calc(expression):
  return eval(expression)

因?yàn)檩斎氲目赡苄允菬o(wú)限的,所以我們肯定要好好測(cè)試一下這個(gè)函數(shù)了。假定我們想了 上百個(gè)test case。又假定我們是用unittest這個(gè)module來(lái)做測(cè)試的。這樣的測(cè)試程序一般會(huì)長(zhǎng)成這樣:

import unittest
class TestStringMethods(unittest.TestCase):
  def test_upper(self):
    self.assertEqual('foo'.upper(), 'FOO')
  def test_isupper(self):
    self.assertTrue('FOO'.isupper())
    self.assertFalse('Foo'.isupper())
  def test_split(self):
    s = 'hello world'
    self.assertEqual(s.split(), ['hello', 'world'])
    # check that s.split fails when the separator is not a string
    with self.assertRaises(TypeError):
      s.split(2)
if __name__ == '__main__':
  unittest.main()

所以我們的目的就是用metaprogramming的方式來(lái)自動(dòng)產(chǎn)生類似上面的測(cè)試類。

先上程序后解釋:

#!/usr/bin/python3
import unittest
def calc(expression):
  return eval(expression)
def add_test(name, asserts):
  def test_method(asserts):
    def fn(self):
      left, right = asserts.split('=')
      expected = str(calc(left))
      self.assertEqual(expected, right)
    return fn
  d = {'test1': test_method(asserts)}
  cls = type(name, (unittest.TestCase,), d)
  globals()[name] = cls
if __name__ == '__main__':
  for i, t in enumerate([
      "1+2=3",
      "3*5*6=90"]):
    add_test("Test%d" % i, t)
  unittest.main()

NB的calc()函數(shù)我們解釋過(guò)了。main這段也比較簡(jiǎn)單:我們用聲明的方式定義了一組測(cè)試,然后通過(guò)unittest來(lái)執(zhí)行。

有點(diǎn)復(fù)雜的是add_test()。我們先來(lái)看看最內(nèi)層的fn(self)這個(gè)方法。邏輯上,它就是把輸入的測(cè)試用例分成兩份,一份是calc()的輸入,一份是我們期待的結(jié)果;然后調(diào)用calc(), 接著用assertEqual()來(lái)測(cè)試。

但是這個(gè)self有點(diǎn)奇怪 – 這里沒(méi)有類,哪里來(lái)的self? 其實(shí)fn(self)確實(shí)是一個(gè)類的方法,只不過(guò)這個(gè)類是我們通過(guò)代碼動(dòng)態(tài)生成的。也就是下面這一行:

cls = type(name, (unittest.TestCase,), d)

這里的type()就是通常我們用來(lái)檢查某個(gè)變量的類型的那個(gè)函數(shù)。只不過(guò)它還有另外一種不大為人知的形式:

class type(name, bases, dict)

這第二種形式,就會(huì)產(chǎn)生一個(gè)新的類型。以我們的程序?yàn)槔褪且評(píng)nit.TestCase為baseclass, 產(chǎn)生了一個(gè)名為TestN的新類型,改類型的實(shí)現(xiàn)由d給出,而d就包含了通過(guò)closure返回的fn(self)這個(gè)方法。只不過(guò)在這個(gè)新類里面,它的名字叫做 test1()。

最后,我們把這個(gè)新產(chǎn)生的類加入到當(dāng)前全局符號(hào)表里面,也就相當(dāng)于上面給出的unittest的例子。

所以,總結(jié)一下。當(dāng)我們運(yùn)行這個(gè)腳本的時(shí)候,這段比較短的代碼會(huì)針對(duì)每一個(gè)測(cè)試的表達(dá)式產(chǎn)生一個(gè)新的測(cè)試類,并動(dòng)態(tài)生成測(cè)試的方法加載到該類里面。unitest從globals中找到這些類并一一執(zhí)行測(cè)試。

上面的例子中,其實(shí)一行一行手打calc(1+2) == 3也沒(méi)什么大不了的。但是當(dāng)你要表達(dá)的邏輯比較復(fù)雜的時(shí)候,metaprogramming的強(qiáng)大就體現(xiàn)出來(lái)了。

總結(jié)

那么,看完這篇文章,我們也成為Tim所說(shuō)的1%的程序猿了!其實(shí),也許他的意思是,99%的編程工作都用不到這樣技巧。在一些特殊的場(chǎng)合,比如編寫某種框架的時(shí)候,metaprogramming會(huì)做到事半功倍。祝你在實(shí)踐中碰到這樣的機(jī)會(huì)。

以上就是本文關(guān)于Python探索之Metaclass初步了解的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:Python編程之Re模塊下的函數(shù)介紹、python中模塊的__all__屬性詳解等,如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!

相關(guān)文章

  • numpy:np.newaxis 實(shí)現(xiàn)將行向量轉(zhuǎn)換成列向量

    numpy:np.newaxis 實(shí)現(xiàn)將行向量轉(zhuǎn)換成列向量

    今天小編就為大家分享一篇numpy:np.newaxis 實(shí)現(xiàn)將行向量轉(zhuǎn)換成列向量,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-11-11
  • python中mpi4py的所有基礎(chǔ)使用案例詳解

    python中mpi4py的所有基礎(chǔ)使用案例詳解

    這篇文章主要介紹了python中mpi4py的所有基礎(chǔ)使用,本文通過(guò)10個(gè)案例給大家詳細(xì)講解,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-08-08
  • 深入理解python虛擬機(jī)之多繼承與?mro

    深入理解python虛擬機(jī)之多繼承與?mro

    在本篇文章當(dāng)中將主要給大家介紹?python?當(dāng)中的多繼承和mro,通過(guò)介紹在多繼承當(dāng)中存在的問(wèn)題就能夠理解在cpython當(dāng)中引入c3算法的原因了,從而能夠幫助大家更好的了理解mro,需要的朋友可以參考下
    2023-05-05
  • 解決Pandas to_json()中文亂碼,轉(zhuǎn)化為json數(shù)組的問(wèn)題

    解決Pandas to_json()中文亂碼,轉(zhuǎn)化為json數(shù)組的問(wèn)題

    今天小編就為大家分享一篇解決Pandas to_json() 中文亂碼,轉(zhuǎn)化為json數(shù)組的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • 解決pytorch中的kl divergence計(jì)算問(wèn)題

    解決pytorch中的kl divergence計(jì)算問(wèn)題

    這篇文章主要介紹了解決pytorch中的kl divergence計(jì)算問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-05-05
  • Python入門教程(二十二)Python的類和對(duì)象

    Python入門教程(二十二)Python的類和對(duì)象

    這篇文章主要介紹了Python入門教程(二十二)Python的類和對(duì)象,Python是一門非常強(qiáng)大好用的語(yǔ)言,也有著易上手的特性,本文為入門教程,需要的朋友可以參考下
    2023-04-04
  • pycharm三個(gè)有引號(hào)不能自動(dòng)生成函數(shù)注釋的問(wèn)題

    pycharm三個(gè)有引號(hào)不能自動(dòng)生成函數(shù)注釋的問(wèn)題

    這篇文章主要介紹了解決pycharm三個(gè)有引號(hào)不能自動(dòng)生成函數(shù)注釋的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • 使用Python進(jìn)行目錄的對(duì)比方法

    使用Python進(jìn)行目錄的對(duì)比方法

    今天小編就為大家分享一篇使用Python進(jìn)行目錄的對(duì)比方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-11-11
  • Python函數(shù)式編程

    Python函數(shù)式編程

    函數(shù)式編程Functional Programming,雖然也可以歸結(jié)到面向過(guò)程的程序設(shè)計(jì),但其思想更接近數(shù)學(xué)計(jì)算。函數(shù)式編程就是一種抽象程度很高的編程范式,純粹的函數(shù)式編程語(yǔ)言編寫的函數(shù)沒(méi)有變量。
    2017-07-07
  • pycharm配置git(圖文教程)

    pycharm配置git(圖文教程)

    這篇文章主要介紹了pycharm配置git(圖文教程),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08

最新評(píng)論