一 面向對象定義
一 面向對象的由來
一、概述
二、詳細發展歷史
二 什麽是面向對象設計以及為什麽要有面向對象
三 類與對象
四 屬性查找
五 綁定到對象方法的特殊之處
六 對象之間的交互
一 面向對象的由來
一、概述
1940年以前:面向機器
最早的程序設計都是采用機器語言來編寫的,直接使用二進制碼來表示機器能夠識別和執行的指令和數 據。簡單來說,就是直接編寫 0 和 1 的序列來代表程序語言。例如:使用 0000 代表 加載(LOAD),0001 代表 存儲(STORE)等。機器語言由機器直接執行,速度快,但一個很明顯的缺點就是:寫起來實在是太困難了,一旦你發現自己 寫錯了,改起來更蛋疼!這樣直接導致程序編寫效率十分低下,編寫程序花費的時間往往是實際運行時間 的幾十倍或幾百倍。
有一個關於機器語言和比爾蓋茨的笑話,是說比爾蓋茨拿著繡花針在一張光盤上戳,把 Windows 給戳出 來了!但如果真的讓你去戳,不要說 Windows,連一個簡單的“Hello world”都要讓人戳到眼睛冒煙!
由於機器語言實在是太難編寫了,於是就發展出了匯編語言。匯編語言亦稱符號語言,用助記符代替機器 指令的操作碼,用地址符號(Symbol)或標號(Label)代替指令或操作數的地址,。匯編語言由於是采用 了助記符號來編寫程序,比用機器語言的二進制代碼編程要方便些,在一定程度上簡化了編程過程。例如 使用 LOAD 來代替 0000,使用 STORE 來代替 0001。
即使匯編語言相比機器語言提升了可讀性,但其本質上還是一種面向機器的語言,編寫同樣困難,也很容 易出錯。相信很多計算機畢業的學生至今都對學校的匯編課程中的練習程序心有余悸。
面向機器的語言通常情況下被認為是一種“低級語言”,為了解決面向機器的語言存在的問題,計算機科 學的前輩們又創建了面向過程的語言。面向過程的語言被認為是一種“高級語言”,相比面向機器的語言 來說,面向過程的語言已經不再關註機器本身的操作指令、存儲等方面,而是關註如何一步一步的解決具體的問題,即:解決問題的過程,這應該也是面向過程說法的來由。
相比面向機器的思想來說,面向過程是一次思想上的飛躍,將程序員從復雜的機器操作和運行的細節中解 放出來,轉而關註具體需要解決的問題;面向過程的語言也不再需要和具體的機器綁定,從而具備了移植 性和通用性;面向過程的語言本身也更加容易編寫和維護。這些因素疊加起來,大大減輕了程序員的負擔, 提升了程序員的工作效率,從而促進了軟件行業的快速發展。
典型的面向過程的語言有:COBOL、FORTRAN、BASIC、C 語言等。
第一次軟件危機:結構化程序設計
根本原因就是一些面向過程語言中的goto語句導致的面條式代碼,極大的限制了程序的規模。結構化程序設計(英語:Structured programming),一種編程範型。它采用子程序(函數就是一種子程序)、代碼區塊、for循環以及while循環等結構,來替換傳統的goto。希望借此來改善計算機程序的明晰性、質量以及開發時間,並且避免寫出面條式代碼。
隨著計算機硬件的飛速發展,以及應用復雜度越來越高,軟件規模越來越大,原有的程序開發方式已經越 來越不能滿足需求了。1960 年代中期開始爆發了第一次軟件危機,典型表現有軟件質量低下、項目無法 如期完成、項目嚴重超支等,因為軟件而導致的重大事故時有發生。例如 1963 年美國 (http://en.wikipedia.org/wiki/Mariner_1) 的水手一號火箭發射失敗事故,就是因為一行 FORTRAN 代碼 錯誤導致的。
軟件危機最典型的例子莫過於 IBM 的 System/360 的操作系統開發。佛瑞德·布魯克斯(Frederick P. Brooks, Jr.)作為項目主管,率領 2000 多個程序員夜以繼日的工作,共計花費了 5000 人一年的工作量,寫出將 近 100 萬行的源碼,總共投入 5 億美元,是美國的“曼哈頓”原子彈計劃投入的 1/4。盡管投入如此巨大, 但項目進度卻一再延遲,軟件質量也得不到保障。布魯克斯後來基於這個項目經驗而總結的《人月神話》 一書,成了史上最暢銷的軟件工程書籍。
為了解決問題,在 1968、1969 年連續召開兩次著名的 NATO 會議,會議正式創造了“軟件危機”一詞, 並提出了針對性的解決方法“軟件工程”。雖然“軟件工程”提出之後也曾被視為軟件領域的銀彈,但後 來事實證明,軟件工程同樣無法解決軟件危機。
差不多同一時間,“結構化程序設計”作為另外一種解決軟件危機的方案被提出來了。 Edsger Dijkstra 於 1968 發表了著名的《GOTO 有害論》的論文,引起了長達數年的論戰,並由此產生了結構化程序設計方 法。同時,第一個結構化的程序語言 Pascal 也在此時誕生,並迅速流行起來。
結構化程序設計的主要特點是拋棄 goto 語句,采取“自頂向下、逐步細化、模塊化”的指導思想。結構 化程序設計本質上還是一種面向過程的設計思想,但通過“自頂向下、逐步細化、模塊化”的方法,將軟 件的復雜度控制在一定範圍內,從而從整體上降低了軟件開發的復雜度。結構化程序方法成為了 1970 年 代軟件開發的潮流。
科學研究證明,人腦存在人類短期記憶一般一次只能記住 5-9 個事物,這就是著名的 7+- 2 原理。結構化 程序設計是面向過程設計思想的一個改進,使得軟件開發更加符合人類思維的 7+-2 特點。
第二次軟件危機:面向對象程序設計
結構化編程的風靡在一定程度上緩解了軟件危機,然而好景不長,隨著硬件的快速發展,業務需求越來越
復雜,以及編程應用領域越來越廣泛,第二次軟件危機很快就到來了。
第二次軟件危機的根本原因還是在於軟件生產力遠遠跟不上硬件和業務的發展,相比第一次軟件危機主要 體現在“復雜性”,第二次軟件危機主要體現在“可擴展性”、“可維護性”上面。傳統的面向過程(包括 結構化程序設計)方法已經越來越不能適應快速多變的業務需求了,軟件領域迫切希望找到新的銀彈來解 決軟件危機,在這種背景下,面向對象的思想開始流行起來。
面向對象的思想並不是在第二次軟件危機後才出現的,早在 1967 年的 Simula 語言中就開始提出來了,但 第二次軟件危機促進了面向對象的發展。 面向對象真正開始流行是在 1980s 年代,主要得益於 C++的功 勞,後來的 Java、C#把面向對象推向了新的高峰。到現在為止,面向對象已經成為了主流的開發思想。
雖然面向對象開始也被當做解決軟件危機的銀彈,但事實證明,和軟件工程一樣,面向對象也不是銀彈, 而只是一種新的軟件方法而已。
雖然面向對象並不是解決軟件危機的銀彈,但和面向過程相比,面向對象的思想更加貼近人類思維的特點, 更加脫離機器思維,是一次軟件設計思想上的飛躍。
二、詳細發展歷史
1940之前:
圖:霍列瑞斯式的打孔機(pantograph),用於1890年的人口普查。第一個編程語言比現代的計算機還早誕生。首先,這種語言是種編碼(en:code)。
於1801年發明的提花織布機(或稱甲卡提花織布機),運用打孔卡上的坑洞來代表縫紉織布機的手臂動作,以便自動化產生裝飾的圖案。
愛達·勒芙蕾絲在1842年至1843年間花費了九個月,將意大利數學家Luigi Menabrea關於查爾斯·巴貝奇新發表機器分析機的回憶錄翻譯完成。她於那篇文章後面附加了一個用分析機計算伯努利數方法的細節,被部分歷史學家認為是世界上第一個電腦程序。
Herman Hollerith在觀察列車長對乘客票根在特定位置打洞的方式後,意識到他可以把信息編碼記載到打孔卡上,隨後根據這項發現使用打孔卡來編碼並紀錄1890年的人口統計數據。
第一個計算機代碼是針對他們的應用面設計的。在20世紀的前十年主要是用十進制來算數,後來人們發現不只是用文字,也可以用數字來表現邏輯。舉例來說,阿隆佐·邱奇曾以公式化(formulaic)的方式表達λ演算。圖靈機是一種紙帶標記(tape-marking)機器(就像電話公司用的那種)操作方法抽象化後的集合。圖靈機這種通過有限數字(finite number)呈現機器的方式,奠定了程序如同馮·諾伊曼結構計算機中的數據一樣地存儲的基礎。但不同於λ演算,圖靈機的代碼並沒有辦法成為高級編程語言的基石,這是是因為它主要的用途是分析算法的復雜度。
就像許多歷史上的"第一次"一樣,第一個現代編程語言也很難界定。最一開始是因為硬件限制而限定了語言,打孔卡允許80行(column)的長度,但某幾行必須用來記錄卡片的順序。FORTRAN則納入了一些與英文字詞相同的關鍵字,像是"IF"、"GOTO"(原字詞為go to),以及"CONTINUE"。之後采用磁鼓(magnetic drum)作為存儲器使用,也代表計算機程序也必須插入(interleave)到磁鼓的轉動(rotation)中。和現今比較起來,這也讓編程語言必須更加依賴硬件(hardware-dependent)。
對部分的人認為必須在"編程語言"的狀態確立之前,根據能力(power)以及可讀性(human-readability)的程度來決定歷史上第一個編程語言是什麽語言。提花織布機和查爾斯·巴貝奇所制作的差分機(en:Difference Engine)都具備在大量限制下,簡單描述機器應運行行為的語言。也有種並非設計給人類運用的受限特定領域語言(en:domain-specific language),是將打孔卡運用到自動演奏鋼琴(en:player piano)上。
1940年代:
最早被確認的現代化、電力引導(electrically powered)的計算機約在1940年代被創造出來。程序員在有限的速度及存儲器容量限制之下,撰寫人工調整(hand tuned)過的匯編語言程序。而且很快就發現到使用匯編語言的這種撰寫方式需要花費大量的腦力(intellectual effort)而且很容易出錯(error-prone)。
康拉德·楚澤於1948年發表了他所設計的Plankalkül編程語言的論文[1]。但是在他有生之年卻未能將該語言實現,而他原本的貢獻也被其他的發展所孤立。
在這段期間被開發出來的重要語言包括有:
- 1943 - Plankalkül (Konrad Zuse)
- 1943 - ENIAC coding system
- 1949 - C-10
1950與1960年代:
有三個現代編程語言於1950年代被設計出來,這三者所派生的語言直到今日仍舊廣泛地被采用:
- Fortran (1955),名稱取自"FORmula TRANslator"(公式翻譯器),由約翰·巴科斯等人所發明;
- LISP,名稱取自"LISt Processor"(枚舉處理器),由約翰·麥卡錫等人所發明;
- COBOL,名稱取自"COmmon Business Oriented Language"(通用商業導向語言),由被葛麗絲·霍普深刻影響的Short Range Committee所發明。
另一個1950年代晚期的裏程碑是由美國與歐洲計算機學者針對"算法的新語言"所組成的委員會出版的ALGOL 60報告(名稱取自"ALGOrithmic Language"(算法語言))。這份報告強化了當時許多關於計算的想法,並提出了兩個語言上的創新功能:
- 嵌套區塊結構:可以將有意義的代碼片段組群成一個區塊(block),而非轉成分散且特定命名的程序。
- 詞匯範圍(lexical scoping):區塊可以有區塊外部無法通過名稱訪問,屬於區塊本身的變量、程序以及函數。
另一個創新則是關於語言的描述方式:
- 一種名為巴科斯-諾爾範式 (BNF)的數學化精確符號被用於描述語言的語法。之後的編程語言幾乎全部都采用類似BNF的方式來描述程序語法中上下文無關的部分。
Algol 60對之後語言的設計上帶來了特殊的影響,部分的語言很快的就被廣泛采用。後續為了開發Algol的擴充子集合,設計了一個名為Burroughs(en:Burroughs large systems)的大型系統。
延續Algol的關鍵構想所產生的成果就是ALGOL 68:
- 語法跟語義變的更加正交(orthogonal),采用匿名的歷程(routines),采用高級(higher-order)功能的遞歸式輸入(typing)系統等等。
- 整個語言及語義的部分都通過為了描述語言而特別設計的Van Wijngaarden grammar來進行正式的定義,而不僅止於上下文無關的部分。
Algol 68一些較少被使用到的語言功能(如同步與並行區塊)、語法快捷方式的復雜系統,以及類型自動強制轉換(coercions),使得實現者興趣缺缺,也讓Algol 68獲得了很難用(diffcult)的名聲。尼克勞斯·維爾特就幹脆離開該設計委員會,另外再開發出更簡單的Pascal語言。
在這段期間被開發出來的重要語言包括有:
- 1951 - Regional Assembly Language
- 1952 - Autocode
- 1954 - FORTRAN
- 1954 - IPL (LISP的先驅)
- 1955 - FLOW-MATIC (COBOL的先驅)
- 1957 - COMTRAN (COBOL的先驅)
- 1958 - LISP
- 1958 - ALGOL 58
- 1959 - FACT (COBOL的先驅)
- 1959 - COBOL
- 1962 - APL
- 1962 - Simula
- 1962 - SNOBOL
- 1963 - CPL (C的先驅)
- 1964 - BASIC
- 1964 - PL/I
- 1967 - BCPL (C的先驅)
1967-1978:確立了基礎範式
1960年代晚期至1970年代晚期的期間中,編程語言的發展也有了重大的成果。大多數現在所使用的主要語言範式都是在這段期間中發明的:
- Simula,於1960年代晚期由奈加特與Dahl以Algol 60超集合的方式發展,同時也是第一個設計支持面向對象進行開發的編程語言。
- C,於1969至1973年間由貝爾實驗室的研究人員丹尼斯·裏奇與肯·湯普遜所開發,是一種早期的系統程序設計(en:system programming)語言。
- Smalltalk,於1970年代中期所開發,是一個完全從零開始(ground-up)設計的面向對象編程語言。
- Prolog,於1972年由Colmerauer、Roussel,以及Kowalski所設計,是第一個邏輯程序語言。
- ML,於1973年由羅賓·米爾納所發明,是一個基於Lisp所建構的多態(polymorphic)類型系統,同時也是靜態類型函數編程語言的先驅。
這些語言都各自演展出自己的家族分支,現今多數現代編程語言的祖先都可以追溯他們其中至少一個以上。
在1960年代以及1970年代中結構化程序設計的優點也帶來許多的爭議,特別是在程序開發的過程中完全不使用GOTO。這項爭議跟語言本身的設計非常有關系:某些語言並沒有包含GOTO,這也強迫程序員必須結構化地編寫程序。盡管這個爭議在當時吵翻了天,但幾乎所有的程序員都同意就算語言本身有提供GOTO的功能,在除了少數罕見的情況下去使用GOTO是種不良的程序風格。結果是之後世代的編程語言設計者發覺到結構化編程語言的爭議實在既乏味又令人眼花撩亂。
在這段期間被開發出來的重要語言包括有:
- 1968 - Logo
- 1970 - Pascal
- 1970 - Forth
- 1972 - C語言
- 1972 - Smalltalk
- 1972 - Prolog
- 1973 - ML
- 1975 - Scheme
- 1978 - SQL (起先只是一種查詢語言,擴充之後也具備了程序結構)
1980年代:增強、模塊、性能
1980年代的編程語言與之前相較顯得更為強大。C++合並了面向對象以及系統程序設計。美國政府標準化一種名為Ada的系統編程語言並提供給國防承包商使用。日本以及其他地方運用了大量的資金對采用邏輯編程語言結構的第五代語言進行研究。函數編程語言社區則把焦點轉移到標準化ML及Lisp身上。這些活動都不是在開發新的範式,而是在將上個世代發明的構想進一步發揚光大。
然而,在語言設計上有個重大的新趨勢,就是研究運用模塊或大型組織化的程序單元來進行大型系統的開發。Modula、Ada,以及ML都在1980年代發展出值得註意的模塊化系統。模塊化系統常拘泥於采用泛型程序設計結構:泛型存在(generics being)、本質(essence),參數化模塊(parameterized modules)。(參閱多態)
盡管沒有出現新的主要編程語言範式,許多研究人員仍就擴充之前語言的構想並將它們運用到新的內容上。舉例來說,Argus以及Emerald系統的語言配合面向對象語言運用到分布式系統上。
1980年代的編程語言實現情況也有所進展。計算機系統結構中RISC的進展假定硬件應當為編譯器設計,而非身為人類的匯編語言程序員。借由中央處理器速度增快的幫助,編譯技術也越來越積極,RISC的進展對高級語言編譯技術帶來不小的關註。
語言技術持續這些發展並邁入了1990年代。
在這段期間被開發出來的重要語言包括有:
- 1980 - Ada
- 1983 - C++ (就像有類別的C)
- 1984 - Common Lisp
- 1985 - Eiffel
- 1986 - Erlang
- 1987 - Perl
- 1988 - Tcl
- 1989 - FL (Backus)
1990年代:互聯網時代
1990年代未見到有什麽重大的創新,大多都是以前構想的重組或變化。這段期間主要在推動的哲學是提升程序員的生產力。許多"快速應用程序開發" (RAD) 語言也應運而生,這些語言大多都有相應的集成開發環境、垃圾回收等機制,且大多是先前語言的派生語言。這類型的語言也大多是面向對象的編程語言,包含有Object Pascal、Visual Basic,以及C#。Java則是更加保守的語言,也具備垃圾回收機制。與其他類似語言相比,也受到更多的觀註。新的腳本語言則比RAD語言更新更好。這種語言並非直接從其他語言派生,而且新的語法更加開放地(liberal)與功能契合。雖然腳本語言比RAD語言來的更有生產力,但大多會有因為小程序較為簡單,但是大型程序則難以使用腳本語言撰寫並維護的顧慮[來源請求]。盡管如此,腳本語言還是網絡層面的應用上大放異彩。
在這段期間被開發出來的重要語言包括有:
- 1990 - Haskell
- 1991 - Python
- 1991 - Visual Basic
- 1993 - Ruby
- 1993 - Lua
- 1994 - CLOS (part of ANSI Common Lisp)
- 1995 - Java
- 1995 - Delphi (Object Pascal)
- 1995 - JavaScript
- 1995 - PHP
- 1997 - REBOL
- 1999 - D
現今的趨勢
編程語言持續在學術及企業兩個層面中發展進化,目前的一些趨勢包含有:
- 在語言中增加安全性與可靠性驗證機制:額外的堆棧檢查、信息流(information flow)控制,以及靜態線程安全。
- 提供模塊化的替代機制:混入(en:mixin)、委派(en:delegates),以及觀點導向。
- 組件導向(component-oriented)軟件開發
- 元編程、反射或是訪問抽象語法樹(en:Abstract syntax tree)
- 更重視分布式及移動式的應用。
- 與數據庫的集成,包含XML及關系數據庫。
- 支持使用Unicode編寫程序,所以源代碼不會受到ASCII字符集的限制,而可以使用像是非拉丁語系的腳本或延伸標點符號。
- 圖形用戶界面所使用的XML(XUL、XAML)。
在這段期間被開發出來的重要語言包括有:
- 2001 - C#
- 2001 - Visual Basic .NET
- 2002 - F#
- 2003 - Scala
- 2003 - Factor
- 2006 - Windows PowerShell
- 2007 - Clojure
- 2009 - Go
- 2014 - Swift (編程語言)
編程語言發展史上的傑出人物
- 約翰·巴科斯,發明了Fortran。
- 阿蘭·庫珀,開發了Visual Basic。
- 艾茲格·迪傑斯特拉,開創了正確運用編程語言(proper programming)的框架。
- 詹姆斯·高斯林,開發了Oak,該語言為Java的先驅。
- 安德斯·海爾斯伯格,開發了Turbo Pascal、Delphi,以及C#。
- 葛麗絲·霍普,開發了Flow-Matic,該語言對COBOL造成了影響。
- 肯尼斯·艾佛森,開發了APL,並與Roger Hui合作開發了J。
- 比爾·喬伊,發明了vi,BSD Unix的前期作者,以及SunOS的發起人,該操作系統後來改名為Solaris。
- 艾倫·凱,開創了面向對象編程語言,以及Smalltalk的發起人。
- Brian Kernighan,與丹尼斯·裏奇合著第一本C程序設計語言的書籍,同時也是AWK與AMPL程序設計語言的共同作者。
- 約翰·麥卡錫,發明了LISP。
- 約翰·馮·諾伊曼,操作系統概念的發起者。
- 丹尼斯·裏奇,發明了C。
- 比雅尼·斯特勞斯特魯普,開發了C++。
- 肯·湯普遜,發明了Unix。
- 尼克勞斯·維爾特,發明了Pascal與Modula。
- 拉裏·沃爾,創造了Perl與Perl 6。
- 吉多·範羅蘇姆,創造了Python。
二 什麽是面向對象設計以及為什麽要有面向對象
就好比精心設計好一條流水線,是一種機械式的思維方式。
優點是:復雜度的問題流程化,進而簡單化(一個復雜的問題,分成一個個小的步驟去實現,實現小的步驟將會非常簡單)
缺點是:一套流水線或者流程就是用來解決一個問題,生產汽水的流水線無法生產汽車,即便是能,也得是大改,改一個組件,牽一發而動全身。
應用場景:一旦完成基本很少改變的場景,著名的例子有Linux內核,git,以及Apache HTTP Server等。
面向對象的程序設計並不是全部。對於一個軟件質量來說,面向對象的程序設計只是用來解決擴展性。
三 類與對象
類即類別、種類,是面向對象設計最重要的概念,對象是特征與技能的結合體,而類則是一系列對象相似的特征與技能的結合體
那麽問題來了,先有的一個個具體存在的對象(比如一個具體存在的人),還是先有的人類這個概念,這個問題需要分兩種情況去看
在現實世界中:先有對象,再有類
世界上肯定是先出現各種各樣的實際存在的物體,然後隨著人類文明的發展,人類站在不同的角度總結出了不同的種類,如人類、動物類、植物類等概念
也就說,對象是具體的存在,而類僅僅只是一個概念,並不真實存在
在程序中:務必保證先定義類,後產生對象
這與函數的使用是類似的,先定義函數,後調用函數,類也是一樣的,在程序中需要先定義類,後調用類
不一樣的是,調用函數會執行函數體代碼返回的是函數體執行的結果,而調用類會產生對象,返回的是對象
1 #python為類內置的特殊屬性 2 類名.__name__# 類的名字(字符串) 3 類名.__doc__# 類的文檔字符串 4 類名.__base__# 類的第一個父類(在講繼承時會講) 5 類名.__bases__# 類所有父類構成的元組(在講繼承時會講) 6 類名.__dict__# 類的字典屬性 7 類名.__module__# 類定義所在的模塊 8 類名.__class__# 實例對應的類(僅新式類中)
四 屬性查找
類有兩種屬性:數據屬性和函數屬性
1. 類的數據屬性是所有對象共享的
2. 類的函數屬性是綁定給對象用的
#類的數據屬性是所有對象共享的,id都一樣 print(id(OldboyStudent.school)) print(id(s1.school)) print(id(s2.school)) print(id(s3.school)) ‘‘‘ 4377347328 4377347328 ‘‘‘ #類的函數屬性是綁定給對象使用的,obj.method稱為綁定方法,內存地址都不一樣 #ps:id是python的實現機制,並不能真實反映內存地址,如果有內存地址,還是以內存地址為準 print(Student.learn) print(s1.learn) print(s2.learn) print(s3.learn) ‘‘‘ <function Student.learn at 0x1021329d8> <bound method Student.learn of <__main__.Student object at 0x1021466d8>> <bound method Student.learn of <__main__.Student object at 0x102146710>> <bound method Student.learn of <__main__.Student object at 0x102146748>> ‘‘‘
在obj.name會先從obj自己的名稱空間裏找name,找不到則去類中找,類也找不到就找父類...最後都找不到就拋出異常
五 綁定到對象方法的特殊之處
1 #改寫 2 class Student: 3 school=‘SkyEdu‘ 4 def __init__(self,name,age,sex): 5 self.name=name 6 self.age=age 7 self.sex=sex 8 def learn(self): 9 print(‘%s is learning‘ %self.name) #新增self.name 10 11 def eat(self): 12 print(‘%s is eating‘ %self.name) 13 14 def sleep(self): 15 print(‘%s is sleeping‘ %self.name) 16 17 18 s1=Student(‘jack‘,‘男‘,18) 19 s2=Student(‘lucy‘,‘女‘,38) 20 s3=Student(‘lee‘,‘男‘,78)
類中定義的函數(沒有被任何裝飾器裝飾的)是類的函數屬性,類可以使用,但必須遵循函數的參數規則,有幾個參數需要傳幾個參數
類中定義的函數(沒有被任何裝飾器裝飾的),其實主要是給對象使用的,而且是綁定到對象的,雖然所有對象指向的都是相同的功能,但是綁定到不同的對象就是不同的綁定方法
強調:綁定到對象的方法的特殊之處在於,綁定給誰就由誰來調用,誰來調用,就會將‘誰’本身當做第一個參數傳給方法,即自動傳值(方法__init__也是一樣的道理)
註意:綁定到對象的方法的這種自動傳值的特征,決定了在類中定義的函數都要默認寫一個參數self,self可以是任意名字,但是約定俗成地寫出self。
類即類型
提示:python的class術語與c++有一定區別,與 Modula-3更像。
python中一切皆為對象,且python3中類與類型是一個概念,類型就是類
1 #類型dict就是類dict 2 >>> list 3 <class ‘list‘> 4 5 #實例化的到3個對象l1,l2,l3 6 >>> l1=list() 7 >>> l2=list() 8 >>> l3=list() 9 10 #三個對象都有綁定方法append,是相同的功能,但內存地址不同 11 >>> l1.append 12 <built-in method append of list object at 0x10b482b48> 13 >>> l2.append 14 <built-in method append of list object at 0x10b482b88> 15 >>> l3.append 16 <built-in method append of list object at 0x10b482bc8> 17 18 #操作綁定方法l1.append(3),就是在往l1添加3,絕對不會將3添加到l2或l3 19 >>> l1.append(3) 20 >>> l1 21 [3] 22 >>> l2 23 [] 24 >>> l3 25 [] 26 #調用類list.append(l3,111)等同於l3.append(111) 27 >>> list.append(l3,111) #l3.append(111) 28 >>> l3 29 [111]
六 對象之間的交互
1 class Garen: #定義英雄蓋倫的類,不同的玩家可以用它實例出自己英雄; 2 camp=‘Demacia‘ #所有玩家的英雄(蓋倫)的陣營都是Demacia; 3 def __init__(self,nickname,aggressivity=58,life_value=455): #英雄的初始攻擊力58...; 4 self.nickname=nickname #為自己的蓋倫起個別名; 5 self.aggressivity=aggressivity #英雄都有自己的攻擊力; 6 self.life_value=life_value #英雄都有自己的生命值; 7 def attack(self,enemy): #普通攻擊技能,enemy是敵人; 8 enemy.life_value-=self.aggressivity #根據自己的攻擊力,攻擊敵人就減掉敵人的生命值。
我們可以仿照garen類再創建一個Riven類
1 class Riven: 2 camp=‘Noxus‘ #所有玩家的英雄(銳雯)的陣營都是Noxus; 3 def __init__(self,nickname,aggressivity=54,life_value=414): #英雄的初始攻擊力54; 4 self.nickname=nickname #為自己的銳雯起個別名; 5 self.aggressivity=aggressivity #英雄都有自己的攻擊力; 6 self.life_value=life_value #英雄都有自己的生命值; 7 def attack(self,enemy): #普通攻擊技能,enemy是敵人; 8 enemy.life_value-=self.aggressivity #根據自己的攻擊力,攻擊敵人就減掉敵人的生命值。
實例出倆英雄
1 >>> g1=Garen(‘草叢倫‘) 2 >>> r1=Riven(‘銳雯雯‘)
交互:銳雯雯攻擊草叢倫,反之一樣
1 >>> g1.life_value 2 455 3 >>> r1.attack(g1) 4 >>> g1.life_value 5 401
一 面向對象定義