前言: oop很是很是很是重要。搞不懂oop,就玩不了python,就算能寫也必定是寫代碼時候喜歡靠猜瞎貓碰死老鼠寫得心很虛。爲何這麼說呢,我也是從面向過程編程到死走過來的,一路def到死,一看到有class的代碼就逃到十萬八千里了不想看,想千方設百計繞過這樣的代碼。不只不肯意看這樣的代碼,並且寫代碼時候很沒思路,總是有一個想找一個本來有的相似的項目或模塊,而後全盤複製過來,在裏面進行扣字修改這種衝動。徹底從0開始親手寫一個稍微複雜的文件是不存在的,作不到這一點(不知道有沒有人相同的感覺)。並且會下載不少pdf教程來學習閱讀,但發現每一個教程關於面向對象總會有兩三章的內容,每當看到這些章節教程來了就迅速結束閱讀了,以爲教程上總是花那麼多章節介紹面向對象幹鳥,我不用面向對象難道不行嗎? 直到認真看了一個同事的代碼和認真看了設計模式和麪向對象後,基本上徹底無此困惑,基本上作到了從不復制,可以從容的從0開始寫一個新的py文件,看py教程時候不只再也不很是恐懼面向對象的章節還特地很是喜歡看這些章節,基本上基礎章節都是跳過專門看教程裏面的面向對象章節。這就是學習oop和設計模式帶給我最大的幫助,十分收益。10個python有9個不會oop8個從不用oop,這是我從公司人員寫代碼得出的規律,即便是月薪2萬以上的人也是面向過程編程到死。通過對面向過程編程的代碼進程改造,得出的規律是我能輕易使公司的任何模塊和項目的代碼減小40%-90%。同時咱們項目也有不少不斷增長的功能和任務,別人一如既往面向過程編程到死,相同的任務,我老是能使用別人五分之一到二分之一的代碼完成別人的全功能,由於代碼少,因此在單位時間能作更多的平臺。這些就是oop爲何重要的緣由。那麼此篇就是介紹,如何輕易使用oop,而不是死記硬背 封裝 繼承 多態 抽象這幾個術語,由於背誦這幾個術語對怎麼轉oop沒有太大幫助,只有真正理解後才知道這些術語的含義。html
爲何總是不會oop,總是容易陷入面向過程編程到死的窘境?學習oop的難點是 oop不是一種語法,他是一種思惟,語法很容易在10分鐘內學會和背誦。思想是抽象的不像語法是具體的,因此這種思惟很難學,有的py人員一生都不會甚至不打算了解它。java
按照四步走的固定公式,能寫模塊就能抽象封裝出一個好用的類。針對只會面向過程編程到死的python人員,按照此公式,能寫模塊就能寫類,能寫項目就能寫框架。python
網上講oop概念的不少,但沒抽象出固定公式步驟,看了那些對轉oo不能起到很大指導做用。據說py簡單,就學py,但py害人就是很鬆散不是強制oop形成不思進取從不用oop寫法不好,py能夠平鋪指令,也能夠抽函數,也能夠寫面向對象。但大部分是前兩種,只會前兩種寫法,對寫生產項目壞處很大,致使寫新模塊和功能須要複製粘貼扣字,重複代碼不少和調用麻煩和改一次邏輯須要改幾百個地方和很差維護,有這些毛病。oop能使單個模塊代碼行數減小40% - 60%,oop加設計模式能使多個相似模塊的代碼行數減小最高達90%行代碼。重要是不須要複製粘貼扣字幾百次,新功能10行能代替讓來150行,修改一處時候不須要學然來修改幾百次容易改漏改錯,心情很煩躁。以上這些減小的行數比例是我修改純面向過程編程項目的不少個模塊文件後得出的結論。c++
函數不是也能複用嗎,只有類才能複用嗎,寫類是否是脫了褲子放屁?根據個人經驗是若是問這兩個的區別,那應該是對基本概念都嚴重牛頭不對馬嘴的產生混淆了。函數和類沒有可比性,函數和類裏面的方法纔有得比。函數複用在不須要依賴外部變量和不須要外部函數(須要動態替換的外部依賴函數)和不須要在一組函數中反覆傳參和return結果的時候,才能比較好的效果,若是要修改一個函數所依賴的外部函數不方便,尤爲是依賴外部全局變量但又有須要多實例方面的需求困惑,純函數更是難以搞定,能寫但必然寫得很曲折。不是全部東西必定要oop,因此能夠根據這條來判斷是否要修改爲oop,而不是籠統的聽網上說簡單的用函數複雜的用類,這沒有判斷依聽說什麼才叫簡單和複雜。同理若是不須要用類的但強行寫類反而是沒有理解透徹面向對象能比原來的寫法帶來什麼好處,無論三七二十一什麼都寫類我是持反對態度的。面向過程的函數的複用是輸入輸出轉換級別的複用做用是y = f(x),面向對象的類的複用是框架級別複用、流程級別的複用,函數是和方法來比,函數和類比是牛頭不對馬嘴的比較,函數的複用和麪向對象級別的複用差遠了。編程
一般老師在講面向對象時候,會講類和對象的關係,而後接着就是開始定義一個類了,老師會在類裏面演示定義幾個屬性。但爲何要在類裏面定義幾個屬性(或者叫成員變量)呢,定義他幹什麼?有什麼好處?全部類都不要屬性能夠嗎,不要屬性好很差?在面向過程編程時候沒有屬性或者成員變量是怎麼繞開解決這個成員變量的? 通常都沒講這幾個緣由,致使學生不知道爲何要oop和oop比opp好在哪裏能解決什麼事情。設計模式
除了這個通用公式,那麼提升oo和代碼水平的方法是看w3school或者菜鳥教程的設計模式教程。每月至少看一次36種設計模式,每月都要看一次。每一種模式都是oop封裝的濃縮精華案例。框架
一、以前寫的這個好久了 編輯器
裏面提到的是三步走:函數
模塊和類的轉換規則是:工具
一、模塊級降爲類
二、全局變量改爲實例屬性,全局的不會被改變的變量相似於那種const的,能夠寫成類屬性(減小點內存存儲能夠)。何時須要類屬性何時須要實例屬性,酌情考慮。
三、而後把函數改爲方法。方法是類裏面的,函數是模塊裏面的。
由於裏面舉得一個例子是一我的,但人的屬性寫的是模塊級全局變量,若是是這種寫法,三步走就能夠oo了。
二、但如今的狀況是不少人不喜歡寫全局變量(不寫全局是爲了儘量模擬多實例,這就不可能用全局變量了,由於全局變量在整個python模塊的命名空間下只有一份;並且是但願從入口函數傳不一樣的參獲得不一樣的運行結果,不但願是經過修改頂層代碼的全局變量來獲得不一樣的運行結果,因此纔會出現儘可能少寫全局變量這種現象了),喜歡一步一步一環套一環的傳參和return來處理業務,那麼這種寫法,若是僅僅按照上面的三步走戰略,就不夠了,由於只執行這三步後 ,只是有了class外殼,但絲毫沒有封裝的概念,這樣作是沒有個卵用的。我最近就看過一些這樣的類,寫的貌合神離,貌像面向對象,但神是面向過程,這種類固然是十分的不必,這種寫法除了在長篇幅的模塊文件中割裂出更小命名空間,使各部分功能緊湊一點之外,由於沒有體現出面向對象帶來的任何優勢,也沒任何意義了,直接在這種寫法方式的面向過程的代碼的基礎上,執行這三步加個class關鍵字,只不過是脫了褲子放屁。
若是是這種思惟來寫的面向過程,那麼三步走還不行,須要從新構思整個流程,即在代碼裏面少return少傳參,多用全局變量,按照這個思路在腦殼裏面過一遍,這一步是發生在腦殼裏面的,不是讓你真在代碼寫全局變量,是爲了先構思出來有哪些傳參和return能夠弄成全局變量,而後再接着上面的三步走戰略,降級命名空間,就是oo了。
因此這個前置的發生在腦殼裏面的過程是不能少的,這一步是整個精神支柱 ,後面三步是修改代碼面貌,腦殼裏面不先打好這一步的草稿就匆忙的執行三步走戰略,寫出這種類來,在一些有五六年開發經驗的老手看來,會以爲寫這個python類是在強行裝逼,代碼有點滑稽。有人問是否是代碼裏面多寫class關鍵字就是面向對象了?大錯特錯,面向對象oop和代碼有沒有class沒有必然關係,他是一種思惟思想不是語法形式,舉例一個使用你們公認的強制面向對象的語言java語言來用面向過程的思惟寫代碼的例子,若是也按這種寫法寫python的類,這種就是屬於無效裝逼類。
下面例子使用java,例舉了兩種寫法,一種是使用面向過程,一種是使用面向對象來寫,不用說,代碼確定有class關鍵字,java沒class不行。
三、那麼總結一下就是四步走了:
0)、若是你的代碼已是按照個人那我的 的那個類那種全局變量加函數的寫法能夠跳過這一步。若是是第2種狀況徹底一環套一環的在每一個函數節點裏面return加傳參的寫法,那麼先須要執行下面這段話。
在你的腦瓜裏面構思,你的面向過程的return 傳參,有哪些儘量多的是能夠弄成全局變量的,這時候不用考慮全局變量是否是須要多份的,由於後面在三步走命名空間降級的時候,這個玩意自動變成了實例屬性,而每一個類的多個實例的的屬性都是互不干擾的,除非了你刻意寫了單例模式。
1)、模塊級降爲類
2)、全局變量改爲實例屬性,全局的不會被改變的變量相似於那種const的,能夠寫成類屬性(減小點內存存儲能夠)。何時須要類屬性何時須要實例屬性,酌情考慮。
3)、而後把函數改爲方法。方法是類裏面的,函數是模塊裏面的。
第0步發生在腦殼裏面,後面三步發生在代碼編輯器裏面。跳過第0步直接進行後面三步,那就會寫出面向過程的廢物裝x滑稽類。
面向對象本質是方法和屬性的封裝,若是不容許寫任何一個實例屬性,把全部屬性綁定所有改成外界傳參給方法,全部原來保存中間狀態的實例屬性所有return給外界保存,那寫這樣的類,基本上是沒個鳥用,廢了面向對象的80%功能優勢,只不過是加個class外殼罷了。
爲何是廢了面向對象80%優勢,面向對象除了封裝不是還有繼承和多態嗎?若是沒有任何實例屬性 ,那麼全部方法就沒有須要訪問實例屬性了,全部方法應該聲明爲靜態方法,對一組純靜態方法的類玩繼承和多態基本上沒有太多意義,若是能理解這個,就能夠想到 隨便查看了100萬個 正確運行的java代碼,能夠得出一個規律:一個方法的前綴永遠不可能同時出現abstract 和 static兩個關鍵字,這兩個是關鍵字是互斥的。靜態方法由類名調用,該方法也不訪問任何實例屬性,也就是是靜態方法與對象自己無關,多態時候靜態方法只會使用父類的方法,不使用子類的方法,在一組純靜態方法的工具類的基礎上玩繼承多態基本上是無卵意義,由於沒有卵的必要性,因此直接在語法層面上禁止這兩個關鍵字同時出現,不然會報錯。
四、面向過程人員調用一個類,應該怎麼想?
若是仍是徹底不熟悉類,對模塊加函數更熟悉,那屢次實例化一個類到底用熟悉的思惟怎麼想象他?上面的是說怎麼寫類,是模塊降級爲類了。調用類時候,思惟也能夠升級,從新把類在腦瓜裏面升級爲模塊級寫法,把實例化構造函數傳參想象爲修改全局變量,調用方法想象爲調用函數。
類能夠實例化無數次,徹底能夠把實例化出來的對象想象爲無數個狀態屬性互不干擾的複製的模塊。 因此回到3,就是爲何要寫類而不是寫模塊加全局變量加函數了,模塊是單例,不一樣的地方使用模塊使用的是模塊的相同的全局變量,小紅用了這個模塊後,修改了全局變量,小明再調用,究竟是不是要重置全局變量狀態,不改,小明是女的了,改了小明成男的,但若是其餘函數調用了性別全局變量,小紅再調用尿尿函數,小紅就變成男的告終果成了站着尿尿不是蹲着尿尿,由於這就很牟盾,因此要進行降維。類是多實例,模塊是單實例。
五、雖然網上都說面向過程轉面向對象很難,要靠領悟和實踐,沒有捷徑可走。但完成基本的面向對象轉變,能夠按照這個公式,嚴格執行四步走戰略。其他的就是多實踐多對比領悟摸索,想玩的精妙須要學習23種設計模式。
六、說完怎麼轉oo的公式了,還必須交代爲何這麼作呢。
有不少人就信口雌黃堅決並堅持地說python面向對象是廢物沒鳥用,python裏面寫class徹底沒有一絲必要,說java要寫類那是java語法規定死了必需要寫class,認爲python在類裏面寫方法和直接在模塊下面寫函數效果徹底100%等同,這麼個說法是由於只是由於他長期只使用面向過程沒有自定義過一次類,作事只顧完成一個功能,不講究任何維護和擴展,胡說八道了,能夠寫函數不是必定要全寫函數,那用c++時候若是無論是什麼項目什麼場景堅持全寫函數,那要c++這種語言存在幹什麼,用c就行了。以前舉了不少例子說明oo和op對比的優勢,大道理就不用講,直接用一個反證法就能輕易反駁這種說法了,光去看看三方包,有哪一個包是純面向過程的?若是真的純面向過程,那個包調用起來確定很是的苦逼。若是沒用,那發明python的人是吃飽了撐着閒的蛋疼加個類進去,他們爲何不移除面向對象?這麼瞎說的人難道是以爲本身已經徹底超越了發明python語言的人和全部開發三方庫的人的認知水平了嗎?