隔壁的Java 世界為了創(chuàng)建一個(gè)對(duì)象搞得雞飛狗跳,這邊的Python解釋器倒是樂(lè)得清閑,。 我作為他的第n任助手正式上崗,。 “老大,有程序員要?jiǎng)?chuàng)建對(duì)象,,怎么辦,?”我向Python解釋器發(fā)出了預(yù)警,,上崗后頭一次遇到這種情況,,我有點(diǎn)緊張,。 class Person: p = Person() p.sayHello('andy') “怕啥,我告訴你怎么做啊,,首先找到Metaclass(元類(lèi)),,用元類(lèi)來(lái)創(chuàng)建Class, 最后用Class對(duì)象來(lái)創(chuàng)建實(shí)例?!? 老大說(shuō)著還給我畫(huà)了個(gè)圖: “不是吧,!剛才還說(shuō)人家Java雞飛狗跳,我看我們這兒也絲毫不差,,一個(gè)Class(如Person)在內(nèi)存中用個(gè)對(duì)象來(lái)表示我理解,,畢竟在我們的世界中,一切都是對(duì)象嘛,, 但是這Metaclass(元類(lèi))是什么鬼,?” “是啊,類(lèi)是一個(gè)對(duì)象,調(diào)用這個(gè)類(lèi)對(duì)象的__new__方法就可以創(chuàng)建出這個(gè)類(lèi)的實(shí)例,。那么問(wèn)題來(lái)了,, 類(lèi)對(duì)象是怎么來(lái)的?怎么把這個(gè)類(lèi)對(duì)象給new 出來(lái),?” 老大沒(méi)有回答,,只是反問(wèn)。 “不是程序員寫(xiě)的嗎,, class Person.....” 我有點(diǎn)底氣不足,。 “程序員寫(xiě)的只是代碼,都是文本而已,,我們?cè)趫?zhí)行的過(guò)程中需要用Metaclass 把這個(gè)Person類(lèi)對(duì)象給創(chuàng)建起來(lái)的,?!?nbsp; “可是我也沒(méi)有看到Person類(lèi)的Metaclass?。?! 他到底在哪兒,?” “那是你沒(méi)有找到, Person類(lèi)中沒(méi)有,,就去它的父類(lèi)中去找,,如果也沒(méi)有,就繼續(xù)向父類(lèi)的父類(lèi)去找,,如果在任何父類(lèi)中都找不到Metaclass,,就去模塊中去找,如果還是找不到,,就用缺省的Metaclass,,即type?!?nbsp; 我按照老大的要求,,去找這個(gè)Metaclass,沒(méi)有找到,,只好用缺省的type了,。 可是我記得這個(gè)type不是個(gè)類(lèi),是個(gè)函數(shù)啊,,可以用來(lái)查看一個(gè)變量的類(lèi)型: >>> type(1) 老大說(shuō):“這個(gè)type啊,,還有另外一個(gè)用法,可以創(chuàng)建其他類(lèi)對(duì)象,,在創(chuàng)建的時(shí)候,,需要三個(gè)參數(shù):” 1. 要?jiǎng)?chuàng)建的類(lèi)對(duì)象的名稱(chēng),例如'Person' 2. 要?jiǎng)?chuàng)建的類(lèi)對(duì)象的父類(lèi),例如(object,) 3. 包含屬性的字典,,即類(lèi)的屬性和方法,。例如{'sayHello': sayHello} 比如,下面這段代碼也創(chuàng)建了一個(gè)類(lèi)對(duì)象Person,,和程序員寫(xiě)的class Person... 效果是一樣的,。 def sayHello(self,name): (友情提示:可左右滑動(dòng)) 嘿,,這個(gè)辦法不錯(cuò)啊,可以在運(yùn)行時(shí),、動(dòng)態(tài)地創(chuàng)建一個(gè)全新的類(lèi)出來(lái),!隔壁的Java雖然也能做到,但是得利用ASM之類(lèi)工具去直接操作字節(jié)碼,,太麻煩了,,我大Python直接通過(guò)普普通通、簡(jiǎn)簡(jiǎn)單單的Python代碼就搞定了,! 這就是動(dòng)態(tài)腳本語(yǔ)言的一個(gè)優(yōu)勢(shì)吧,! 之前聽(tīng)說(shuō)過(guò)元編程,現(xiàn)在應(yīng)該就是元編程了吧,?但是這個(gè)Metaclass到底有什么用處呢,? 程序員為什么不直接在代碼中寫(xiě)class Person..... 這樣的代碼? 這樣多直觀啊,。 老大說(shuō):“有些程序員會(huì)自定義Metaclass,,這些自定義的Metaclass 主要做這些事情:” 1. 攔截類(lèi)的創(chuàng)建 2. 讀取類(lèi)的信息,可能做修改 3. 返回新的類(lèi),。 攔截類(lèi)的創(chuàng)建,? 為什么有這樣“變態(tài)”的需求? 我真想看看一個(gè)自定義的Metaclass,,看看它到底是怎么“變態(tài)”的,。 沒(méi)多久,機(jī)會(huì)來(lái)了,,又要?jiǎng)?chuàng)建對(duì)象了,。 from django.db import models 在Employee中沒(méi)有看到Metaclass, 我就去父類(lèi)Model中去尋找,運(yùn)氣不錯(cuò),,一下子就找到了metaclass ,,叫做ModelBase: class Model(metaclass=ModelBase): 趕緊去看ModelBase的代碼,唉,,實(shí)在是有點(diǎn)復(fù)雜了,,讓我看得頭暈。 老大說(shuō):“你不用花費(fèi)時(shí)間了,你的前任的前任曾經(jīng)研究過(guò)它,,是為了實(shí)現(xiàn)ORM ,!” “ORM?” “就是對(duì)象和關(guān)系數(shù)據(jù)庫(kù)的映射,。你想想,,程序員創(chuàng)建的Python對(duì)象想要保存到數(shù)據(jù)庫(kù)中,該怎么辦,?“ 老大問(wèn)道,。 ”那還不簡(jiǎn)單,程序員可以寫(xiě)SQL代碼啊,,insert into employee(name,age) values(?,?),,其中包含那個(gè)Employee對(duì)象的name ,age的值不就行了?“ ”那樣就有點(diǎn)笨拙了,,你再想想,,能不能簡(jiǎn)化程序員的工作,別讓他們?nèi)?xiě)這些煩人的,、容易出錯(cuò)的SQL代碼,?能不能讓框架來(lái)做這件事?“ 老大寫(xiě)了兩行代碼。 employee = Employee(name='andy',age=20) “看看,,程序員只要把對(duì)象創(chuàng)建出來(lái),調(diào)用下save方法就行了,,SQL語(yǔ)句就會(huì)形成,,保存到數(shù)據(jù)庫(kù)中?!?/span> (注:這里略過(guò)了數(shù)據(jù)庫(kù)連接的管理) “難道ModelBase這個(gè)元類(lèi)在后面做‘手腳',?”我似乎有點(diǎn)理解了。 ”沒(méi)錯(cuò),,你看到這些Employee類(lèi)的屬性沒(méi)有,? 就是程序員寫(xiě)的那些name, age...... 程序員這么寫(xiě),其實(shí)就是在告訴ModelBase,,尊敬的Metaclass 啊,, 這些都是數(shù)據(jù)庫(kù)的列啊,列名是 name, 類(lèi)型是char(50) ,, 還有個(gè)列名是age,,是個(gè)整數(shù)?!?nbsp; “那個(gè)MetaClass ,,對(duì),就是ModelBase會(huì)讀取這些列名、類(lèi)型,,并且記錄下來(lái),。 有了列名的信息,將來(lái)就可以形成insert, update,delete等SQL語(yǔ)句了,。對(duì)不對(duì),?” 原來(lái)如此!看來(lái)ModelBase在創(chuàng)建Employee類(lèi)對(duì)象的時(shí)候,,“偷偷地”讀取了Employee類(lèi)的定義信息,,這樣才能在背后實(shí)現(xiàn)ORM! 我按照老大的指示,,調(diào)用ModelBase的__new__方法,,創(chuàng)建了Employee類(lèi)對(duì)象。 接下來(lái)又調(diào)用Employee類(lèi)對(duì)象的__new__方法,,創(chuàng)建了Employee實(shí)例對(duì)象,。 employee = Employee(name='andy',age=20) 當(dāng)程序員調(diào)用employee.save()方法的時(shí)候,正如老大所說(shuō),,神奇的魔法發(fā)生了,,一條sql語(yǔ)句形成,并且發(fā)送給了數(shù)據(jù)庫(kù)去執(zhí)行,。 我感慨到:“這Python的元編程還是真是不錯(cuò)啊,,能在運(yùn)行時(shí)動(dòng)態(tài)地修改類(lèi),比隔壁的Java強(qiáng)多了,!” “Python元編程的技術(shù)不僅僅是Metaclass,,還多著呢,你慢慢學(xué)吧,!” |
|