據廖雪峰python3教程----python學習第十二天

來源:互聯網
上載者:User

標籤:python   類   資料封裝   類和執行個體   


使用模組

Python本身就內建了很多非常有用的模組,只要安裝安裝完畢,這些模組就可以立刻使用。

我們以內建的 sys 模組為例,編寫一個 hello 的模組:

‘a test module‘      # 一個字串表示文檔注釋,任何模組代碼的第一個字串都被視為模組的文檔注釋__author__=‘xiaoming‘   #作者名 可以刪除 上面的也可以不要import sys                    #匯入 sys 模組def test():    args = sys.argv    if len(args)==1:            print(‘Hello,world!‘)    elif len(args)==2:            print(‘Hello,%s‘%args[1])    else:            print("Too many argumments!")if __name__  == ‘__main__‘:    test()


sys模組有一個 argv 變數,用list 儲存了命令的所有參數。argv至少有一個元素,以你為第一個參數永遠是該  .py 檔案的名稱,例如:

運行  

E:\Python>python lianxi.py  獲得的 sys.argv 就是 [‘lianxi.py‘]

運行  

E:\Python>python lianxi.py Mingtian 獲得的sys。argv 就是[‘lianxi.py ‘,‘Mingtian‘]

最後,注意到這兩行代碼:

if __name__==‘__main__‘:    test()


當我們在命令列運行 lianxi 模組檔案時,python 解譯器把一個特殊變數 __name__置為__main__,而如果在其他地方匯入該lianxi 模組時,if 前段將失敗,因此,這種if 測試可以讓一個模組通過命令列運行一個額外的代碼,最常見的就是運行測試。

用命令號運行 lianxi.py :

E:\Python>python lianxi.pyHello,world!
E:\Python>python lianxi.py MingtianHello,Mingtian


啟動python互動環境,再匯入練習模組:

>>> import lianxi>>> lianxi.test()Hello,world!


匯入時沒有列印 hello,world,因為沒事執行test()函數。調用test()函數才會列印 hello,world


範圍

在一個模組中,我們可能會定義很多函數和變數,擔憂的函數和變數我們希望給別人使用,有的函數和變數我們希望僅僅在模組內部使用。在Python中,是通過 _ 首碼來實現的。

正常的函數和變數名是公開的(public),可以被直接飲用,比如:abc,x123,PI等:

類似__xxx__這應的函數或變數就是非公開的(private),不應該被直接飲用, 比如_abc,__abc等:

之所以我們說,private函數和變數“不應該”被直接飲用,而不是“不能”被直接飲用,是因為Python並沒有一種方法可以完全限制訪問private函數或變數,但是,從變成習慣上不應該應用private函數或變數。


private函數或變數不應該被別人引用,那它們有什麼用呢?:

def _private_1(name):    return ‘Hello, %s‘ %namedef _private_2(name):          return ‘Hi, %s‘ %name      def greeting(name):    if len(name) > 3:            return _private_1(name)    else:            return _private_2(name)


我們在模組裡公開greeting()函數,而把內部邏輯用private函數隱藏起來了,這樣,調用greeting()函數不用關心內部的private函數細節,這也是一種非常有用的代碼封裝和抽象的方法,即:


外部不需要引用的函數全部定義成private,只有外部需要引用的函數才定義為public。


物件導向編程

物件導向編程 ------ Object Oriented Programming,簡稱OOP,是一種程式設計思想。OOP把對象作為程式的基本單元,一個對象包含了資料和操作資料的函數。

面向過程的程式設計把電腦程式視為一系列的命令集合,及一組函數的順序執行。為了簡化程式設計,面向過程把函數繼續切為分子函數,即把大塊函數通過切割成小塊函數來降低體統的複雜度。

而物件導向的程式設計把電腦程式視為一組對象的集合,而每個對象都可以接受其他對象發過來的訊息,並處理這些訊息,電腦程式的執行 就是一系列訊息在各個對象之間傳遞。

在python中,所有資料類型都可以視為對象,當然也可以自訂對象。自訂的的資料類型就是物件導向中的類class的概念。


Eg:顯示一個學生的成績

(1)面向過程:

>>> std1 = {‘name‘:‘Micheal‘,‘score‘:98}>>> std2 = {‘name‘:‘Bob‘,‘score‘:81}>>> def print_score(std):             print(‘%s:%s‘%(std[‘name‘],std[‘score‘]))

    

>>> print_score(std1)Micheal:98>>> print_score(std2)Bob:81


(2)採用物件導向的程式設計思想,我們首選思考的不是程式的執行流程,而是student這種資料類型應該被視為一個對象,這個對象擁有 name 和 score 這兩個屬性(Property)。如果要列印一個學生的成句,首相必須建立出這個學生對應的對象,然後,給對象發一個 print_score 訊息,讓自己把自己的資料列印出來。

class Student(object):        def __init__(self,name,score):                  self.name = name                  self.score = score        def print_score(self):                        print(‘%s:%s‘%(self.name,self.score))


給對象發訊息實際上就是調用對象對應的關聯函數,我們稱之為對象的方法(Method)。物件導向的程式寫出來就想這樣:

>>> bart = Student(‘Bart‘,59)>>> lisa = Student(‘Lisa‘,98)>>> bart.print_score()Bart:59>>> lisa.print_score()Lisa:98


類和執行個體

物件導向最重要的概念就是類(Class)和執行個體(Instance),必須牢記類是抽象的模板,比如Student類,而執行個體是根據類建立出來的一個個具體的“對象”,每個對象都擁有相同的方法,但各自的資料可能不同。

在Python中,定義類是通過class關鍵字:

>>> class Student(object):     pass


class後面緊接著是類名,即Student,類名通常是大寫開頭的單詞,緊接著是(object),表示該類是從哪個類繼承下來的,

通常,如果沒有合適的繼承類,就使用object類,這是所有類最終都會繼承的類。


定義好了Student類,就可以根據Student類建立出Student的執行個體,建立執行個體是通過類名+()實現的:

>>> bart = Student(‘xiaoming‘,66)>>> bart<__main__.Student object at 0x02CEAA70>>>> Student<class ‘__main__.Student‘>



可以看到,變數bart指向的就是一個Student的執行個體,後面的0x10a67a590是記憶體位址,每個object的地址都不一樣,而Student本身則是一個類。


可以自由地給一個執行個體變數綁定屬性,比如,給執行個體bart綁定一個name屬性:

>>> bart.name = ‘xaioming‘>>> bart.name‘xaioming‘



由於類可以起到模板的作用,因此,可以在建立執行個體的時候,把一些我們認為必須綁定的屬性強制填寫進去。通過定義一個特殊的__init__方法,在建立執行個體的時候,就把namescore等屬性綁上去:

class Student(object):        def __init__(self,name,score):                  self.name = name                        self.score = score


注意__init__方法的第一個參數永遠是self,表示建立的執行個體的本身,因此,在__init__方法內部,就可以把各種屬性綁定帶self,因為self就指向建立的執行個體本身。有了 __inlt__方法在建立執行個體的時候,就不能傳入空的參數了,必須傳入與__init__方法匹配的參數,但self不需要傳,Python解譯器自己會把執行個體變數穿進去:

>>> bart = Student(‘xiaoming‘,66)>>> bart.name‘xiaoming‘>>> bart.score66


和普通的函數相比,在類中定義的函數只有一點不同,就是第一個參數永遠是執行個體變數self,並且,調用時,不用傳遞該參數。除此之外,類的方法和普通函數沒有什麼區別,所以,你任然可以用預設參數、可變參數、關鍵字參數和命名關鍵字參數


資料封裝

物件導向編程的一個重要特點就是資料封裝。在上面的student類中,每個執行個體就擁有各自的name 和 score 這些資料。

我們可以通過函數來訪問這些資料,比如列印一個學生的成績:

     def print_score(self):          print(‘%s:%s‘%(self.name,self.score))
>>> def print_score(std):           print(‘%s: %s‘ % (std.name, std.score))


>>> print_score(bart)Bart Simpson: 59



既然Student執行個體本身就擁有這些資料,要訪問這些資料,就沒有必要從外面的函數去訪問,可以直接在Student類的內部定義訪問資料的函數,這樣,就把‘‘資料"給封裝起來了。這些封裝資料的函數是和Student類本身關聯起來的,我們稱之為類的方法:

class Student(object):        def __init__(self,name,score):                  self.name = name                  self.score = score        def print_score(self):                         print(‘%s:%s‘%(self.name,self.score))>>> bart=Student(‘xiaoming‘,99)>>> bart.print_score()xiaoming:99


 

訪問限制

在class內部,可以有屬性和方法,而外部代碼可以通過直接調用執行個體變數的方法來操作資料,這樣,就隱藏了內部的複雜 邏輯。


但是,從前面Student類的定義來看,外部代碼還是可以自由地修改一個執行個體的name,score屬性:

>>> bart=Student(‘Bart‘,98)>>> bart.score98>>> bart.score=59>>> bart.score59



如果要讓內部屬性,可以把屬性的名稱前加上兩個底線__,在python中,執行個體的變數名如果以__開頭,就變成了一個私人變數(private),只有內部可以訪問,外部不能訪問,所以,我們把Student類改一改:

class Student(object):         def __init__(self,name,score):          self.__name = name          self.__score = score              def print_score(self):          print(‘%s:%s‘%(self.__name,self.__score))     def get_grade(self):               if self.score>=90:                    return ‘A‘               elif self.score>=60:                    return ‘B‘               else:                    return ‘C‘

改完後,對於外部代碼來說,沒什麼變動,但是已經無法從外部存取執行個體變數.__name執行個體變數.__score了:

 >>> bart=Student(‘Bart‘,98) >>> bart.__name Traceback (most recent call last) :  File "<pyshell#11>", line 1, in <module>     bart.__nameAttributeError: ‘Student‘ object has no attribute ‘__name‘

這樣就確保了外部代碼不能隨意修改對象內部的狀態,這樣通過訪問限制的保護,代碼更加健壯。

但是如果外部代碼要擷取name和score怎麼辦?可以給Student 類增加 get_name 和 get_score 這樣的方法:

class Student(object):    ...    def get_name(self):        return self.__name    def get_score(self):        return self.__score


如果又要允許外部代碼修改score怎麼辦?可以再給Student類增加set_score方法:

class Student(object):    ...        def set_score(self, score):           self.__score = score

在方法中,可以對參數做檢查,避免傳入無效的參數:

class Student(object):    ...        def set_score(self, score):                if 0 <= score <= 100:                          self.__score = score                else:                          raise ValueError(‘bad score‘)




需要注意的是,在Python中,變數名類似__xxx__的,也就是以雙底線開頭,並且以雙底線結尾的,是特殊變數,特殊變數是可以直接存取的,不是private變數,所以,不能用__name____score__這樣的變數名。


有些時候,我們會看到以一個底線開頭的執行個體變數名,比如_name,這樣的執行個體變數外部是可以訪問的,但是,按照約定俗成的規定,當你看到這樣的變數時,意思就是,“雖然我可以被訪問,但是,請把我視為私人變數,不要隨意訪問”。


雙底線開頭的執行個體變數是不是一定不能從外部存取呢?其實也不是。不能直接存取__name是因為Python解譯器對外把__name變數改成了_Student__name,所以,仍然可以通過_Student__name來訪問__name變數:

>>> bart._Student__name‘Bart Simpson‘



 


因為不同版本的Python解譯器可能會把__name改成不同的變數名。

總的來說就是,Python本身沒有任何機制阻止你幹壞事,一切全靠自覺。





本文出自 “啟思·朝聖者” 部落格,請務必保留此出處http://dearch.blog.51cto.com/10423918/1762873

據廖雪峰python3教程----python學習第十二天

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.