當前位置:
首頁 > 知識 > 兩句話輕鬆掌握 Python 最難知識點

兩句話輕鬆掌握 Python 最難知識點

作者:劉羽沖

來源:https://segmentfault.com/a/1190000011447445

千萬不要被所謂"元類是99%的python程序員不會用到的特性"這類的說辭嚇住。因為每個中國人,都是天生的元類使用者

學懂元類,你只需要知道兩句話:

道生一,一生二,二生三,三生萬物

我是誰?我從哪來里?我要到哪裡去?

在python世界,擁有一個永恆的道,那就是"type",請記在腦海中,type就是道。如此廣袤無垠的python生態圈,都是由type產生出來的。

道生一,一生二,二生三,三生萬物。

即是 type

即是 metaclass(元類,或者叫類生成器)

即是 class(類,或者叫實例生成器)

即是 instance(實例)

萬物即是 實例的各種屬性與方法,我們平常使用python時,調用的就是它們。

道和一,是我們今天討論的命題,而二、三、和萬物,則是我們常常使用的類、實例、屬性和方法,用hello world來舉例:

輸出效果:

這就是一個標準的"二生三,三生萬物"過程。從類到我們可以調用的方法,用了這兩步。

那我們不由自主要問,類從何而來呢?回到代碼的第一行。

class Hello其實是一個函數的"語義化簡稱",只為了讓代碼更淺顯易懂,它的另一個寫法是:

這樣的寫法,就和之前的Class Hello寫法作用完全相同,你可以試試創建實例並調用

輸出效果:

我們回頭看一眼最精彩的地方,道直接生出了二

Hello = type("Hello", (object,), dict(say_hello=fn))

這就是"道",python世界的起源,你可以為此而驚嘆。

注意它的三個參數!暗合人類的三大永恆命題:我是誰,我從哪裡來,我要到哪裡去。

第一個參數:我是誰。 在這裡,我需要一個區分於其它一切的命名,以上的實例將我命名為"Hello"

第二個參數:我從哪裡來

在這裡,我需要知道從哪裡來,也就是我的"父類",以上實例中我的父類是"object"——python中一種非常初級的類。

第三個參數:我要到哪裡去

在這裡,我們將需要調用的方法和屬性包含到一個字典里,再作為參數傳入。以上實例中,我們有一個say_hello方法包裝進了字典中。

值得注意的是,三大永恆命題,是一切類,一切實例,甚至一切實例屬性與方法都具有的。理所應當,它們的"創造者",道和一,即type和元類,也具有這三個參數。但平常,類的三大永恆命題並不作為參數傳入,而是以如下方式傳入

造物主,可以直接創造單個的人,但這是一件苦役。造物主會先創造"人"這一物種,再批量創造具體的個人。並將三大永恆命題,一直傳遞下去。

"道"可以直接生出"二",但它會先生出"一",再批量地製造"二"。

type可以直接生成類(class),但也可以先生成元類(metaclass),再使用元類批量定製類(class)。


元類——道生一,一生二

一般來說,元類均被命名後綴為Metalass。想像一下,我們需要一個可以自動打招呼的元類,它裡面的類方法呢,有時需要sayHello,有時需要sayHi,有時又需要saySayolala,有時需要sayNihao。

如果每個內置的say_xxx都需要在類裡面聲明一次,那將是多麼可怕的苦役! 不如使用元類來解決問題。

以下是創建一個專門"打招呼"用的元類代碼:

記住兩點:

1、元類是由"type"衍生而出,所以父類需要傳入type。【道生一,所以一必須包含道

2、元類的操作都在new中完成,它的第一個參數是將創建的類,之後的參數即是三大永恆命題:我是誰,我從哪裡來,我將到哪裡去。 它返回的對象也是三大永恆命題,接下來,這三個參數將一直陪伴我們。

new中,我只進行了一個操作,就是

它跟據類的名字,創建了一個類方法。比如我們由元類創建的類叫"Hello",那創建時就自動有了一個叫"say_Hello"的類方法,然後又將類的名字"Hello"作為默認參數saying,傳到了方法裡面。然後把hello方法調用時的傳參作為value傳進去,最終列印出來。

那麼,一個元類是怎麼從創建到調用的呢?

來!一起根據道生一、一生二、二生三、三生萬物的準則,走進元類的生命周期吧!

輸出為

注意:通過元類創建的類,第一個參數是父類,第二個參數是metaclass

普通人出生都不會說話,但有的人出生就會打招呼說"Hello","你好","sayolala",這就是天賦的力量。它會給我們面向對象的編程省下無數的麻煩。

現在,保持元類不變,我們還可以繼續創建Sayolala, Nihao類,如下:

輸出

也可以說中文

輸出

再來一個小例子:

現在我們列印一下L

而普通的list沒有add()方法

太棒了!學到這裡,你是不是已經體驗到了造物主的樂趣?

python世界的一切,盡在掌握。


年輕的造物主,請隨我一起開創新世界。

我們選擇兩個領域,一個是Django的核心思想,"Object Relational Mapping",即對象-關係映射,簡稱ORM。

這是Django的一大難點,但學完了元類,一切變得清晰。你對Django的理解將更上一層樓!

另一個領域是爬蟲領域(黑客領域),一個自動搜索網路上的可用代理,然後換著IP去突破別的人反爬蟲限制。

這兩項技能非常有用,也非常好玩!


挑戰一:通過元類創建ORM

準備工作,創建一個Field類

它的作用是

在Field類實例化時將得到兩個參數,name和column_type,它們將被綁定為Field的私有屬性,如果要將Field轉化為字元串時,將返回"Field:XXX" , XXX是傳入的name名稱。

準備工作:創建StringField和IntergerField

它的作用是

在StringField,IntegerField實例初始化時,時自動調用父類的初始化方式。


道生一

它做了以下幾件事

創建一個新的字典mapping

將每一個類的屬性,通過.items()遍歷其鍵值對。如果值是Field類,則列印鍵值,並將這一對鍵值綁定到mapping字典上。

將剛剛傳入值為Field類的屬性刪除。

創建一個專門的mappings屬性,保存字典mapping。

創建一個專門的table屬性,保存傳入的類的名稱。


一生二

如果從Model創建一個子類User:

這時

id= IntegerField("id")就會自動解析為:

Model.setattr(self, "id", IntegerField("id"))

因為IntergerField("id")是Field的子類的實例,自動觸發元類的new,所以將IntergerField("id")存入mappings並刪除這個鍵值對。


二生三、三生萬物

當你初始化一個實例的時候並調用save()方法時候

這時先完成了二生三的過程:

先調用Model.setattr,將鍵值載入私有對象

然後調用元類的"天賦",ModelMetaclass.new,將Model中的私有對象,只要是Field的實例,都自動存入u.mappings

接下來完成了三生萬物的過程:

通過u.save()模擬資料庫存入操作。這裡我們僅僅做了一下遍歷mappings操作,虛擬了sql並列印,在現實情況下是通過輸入sql語句與資料庫來運行。

輸出結果為

年輕的造物主,你已經和我一起體驗了由"道"演化"萬物"的偉大曆程,這也是Django中的Model版塊核心原理。

接下來,請和我一起進行更好玩的爬蟲實戰(嗯,你現在已經是初級黑客了):網路代理的爬取吧!


挑戰二:網路代理的爬取

準備工作,先爬個頁面玩玩

請確保已安裝requests和pyquery這兩個包。

這裡,我們利用request包,把百度的源碼爬了出來。

試一試抓百度

把這一段粘在get_page.py後面,試完刪除

試一試抓代理

把這一段粘在get_page.py後面,試完刪除

接下來進入正題:使用元類批量抓取代理


批量處理抓取代理

道生一:元類的new中,做了四件事:

將"crawl_"開頭的類方法的名稱推入ProxyGetter.CrawlName

將"crawl_"開頭的類方法的本身推入ProxyGetter.CrawlFunc

計算符合"crawl_"開頭的類方法個數

刪除所有符合"crawl_"開頭的類方法

怎麼樣?是不是和之前創建ORM的mappings過程極為相似?

一生二:類裡面定義了使用pyquery抓取頁面元素的方法

分別從三個免費代理網站抓取了頁面上顯示的全部代理。

如果對yield用法不熟悉,可以查看:

廖雪峰的python教程:生成器

二生三:創建實例對象crawler

三生萬物:遍歷每一個CrawlFunc

在ProxyGetter.CrawlName上面,獲取可以抓取的的網址名。

觸發類方法ProxyGetter.getrawproxies(site)

遍歷ProxyGetter.CrawlFunc,如果方法名和網址名稱相同的,則執行這一個方法

把每個網址獲取到的代理整合成數組輸出。

那麼。。。怎麼利用批量代理,衝擊別人的網站,套取別人的密碼,狂發廣告水貼,定時騷擾客戶? 呃!想啥呢!這些自己悟!如果悟不到,請聽下回分解!


年輕的造物主,創造世界的工具已經在你手上,請你將它的威力發揮到極致!

請記住揮動工具的口訣:

道生一,一生二,二生三,三生萬物

我是誰,我來自哪裡,我要到哪裡去

題圖:pexels,CC0 授權。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 編程派 的精彩文章:

也談 Python 的中文編碼問題

TAG:編程派 |