首頁  >  文章  >  後端開發  >  Python基礎學習之類的介紹

Python基礎學習之類的介紹

零下一度
零下一度原創
2017-07-19 23:47:441260瀏覽

  在Python中,首字母大寫的名稱指的是類別。這個類別定義中的括號是空的,因為我們要從空白建立這個類別。我們寫了一個文件字串,對這個類別的功能作了描述。類別中的函數稱為方法。

  以Student類別為例,在Python中,定義類別是透過class關鍵字:

class Student(object) :

    pass

  class後面緊接著是個類別名,即Student,類別名稱通常是大寫開頭的單詞,緊接著是( object),表示該類別是從哪個類別繼承下來的,通常,如果沒有合適的繼承類,就使用object類,這是所有類別最終都會繼承的類別。

9.1.1建立類別

,這是一種約定,旨在避免Python預設方法與普通方法發生名稱衝突。在這個方法的定義中,形參self 必不可少,也必須位於其他形參的前面。

class Student(object):

 

    def __init__( self, name, score):

        self.name = name

       __init__() 是一個特殊的方法,建立新實例時,Python都會自動運行它。開頭和結尾各有

兩個底線

  2.每個與類別相關聯的方法呼叫都會自動傳遞實參self ,它是一個指向實例本身的引用,讓實例能夠存取類別中的屬性和方法。 self 會自動傳遞,因此我們不需要傳遞它。   3.以self 為前綴的變數都可供類別中的所有方法使用,我們也可以透過類別的任何實例來存取這些變數。   4.self.name= name像這樣可透過實例存取的變數稱為屬性

  5.物件導向程式設計的一個重要特點就是資料封裝。可以直接在類別的內部定義存取資料的函數,這樣,就把「資料」給封裝起來了。這些

封裝資料的函數

是和Student類別本身是關聯起來的,我們稱之為類別的方法.

9.1.2根據類別建立實例

  我們通常可以認為首字母大寫的名稱(如Dog )指的是類,而小寫的名稱(如my_dog )指的是根據類別創建的實例。   1、要存取實例的屬性,可使用

句點表示法

,我們寫如下程式碼來存取my_dog 的屬性name 的值。

  my_dog.name

  句點表示法在Python中很常用,這種語法示範了Python如何獲悉屬性的值。   2、根據Dog 類別建立實例後,就可以使用句點表示法來呼叫Dog 類別中定義的任何方法。

  3、可依需求根據類別建立任意數量的實例。

9.2使用類別和實例

  1.你需要執行的一個重要任務是修改實例的屬性。你可以直接修改實例的屬性,也可以寫法以特定的方式進行修改。

  2.類別是建立實例的模板,而實例則是一個具體的對象,各個實例擁有的資料都互相獨立,互不影響;方法就是與實例綁定的函數,和普通函數不同,方法可以直接存取實例的數據;透過在實例上呼叫方法,我們就直接操作了物件內部的數據,但無需知道方法內部的實作細節。和靜態語言不同,Python允許對實例變數綁定任何數據,也就是說,對於兩個實例變量,雖然它們都是同一個類別的不同實例,但擁有的變數名稱都可能不同。

9.2.1為類別設定初始值

      類別中的每個屬性都必須有初始值,即使這個值是0或空字串。在某些情況下,如設定預設值時,在方法__init__() 內指定這種初始值是可行的;如果你對某個屬性這樣做了,就無需包含為它提供初始值的形參。

直接在class中定義屬性,這種屬性是類別屬性:

#class Student(object):

name = 'Student'

#

  在編寫程式的時候,千萬不要把實例屬性和類別屬性使用相同的名字,因為相同名稱的實例屬性將屏蔽掉類別屬性,但是當你刪除實例屬性後,再使用相同的名稱,訪問到的將是類別屬性。

9.2.2修改屬性的值

  可以以三種不同的方式修改屬性的值:

  1.直接透過實例進行修改;

  2.透過方法進行設定;

  3.透過方法進行遞增(增加特定的值)。

9.2.3存取限制

  1.在Class內部,可以有屬性和方法,而外部程式碼可以透過直接呼叫實例變數的方法來操作數據,這樣,就隱藏了內部的複雜邏輯。

  2.如果要讓內部屬性不被外部訪問,可以把屬性的名稱前加上兩個下劃線__,在Python中,實例的變數名稱如果以__開頭,就變成了一個私有變數(private),只有內部可以訪問,外部不能訪問。

class Student(object):

#    def __init__(self, name, score):

        self.__name = name

        self.__score = score

 

    def print_score(self):

   1% (  ) name% ( , self.__score))

  3.改完後,對於外部程式碼來說,沒什麼變動,但是已經無法從外部存取實例變數.__name和實例變數.__score了:

>>> bart = Student('Bart Simpson', 98)

#>> ;> bart.__name

Traceback (most recent call last):

  File "", line 1, in

AttributeError: 'Student' object has no attribute '__name'

  4.這樣就確保了外部程式碼不能隨意修改物件內部的狀態,這樣透過存取限制的保護,程式碼更加健壯。但如果外部程式碼要取得name和score,可以為Student類別增加get_name和get_score這樣的方法:

  5.如果又要允許外部程式碼修改score,可以再給Student類別增加set_score方法:

class Student(object):

    ...

    def get_name(self):

        return self.__name

 

   return #        return self.__score

class Student(object):  6.和原來直接呼叫參數相比,在方法中,可以對參數做檢查,避免傳入無效的參數:

    ...

    def set_score(self, score):

     score

class Student(object):

    ...

    def set_score(self, score):

     if  0 <= score <= 100:

            self.__score = score

      )

#

  7.需要注意的是,在Python中,變量名類似__xxx__的,也就是以雙下劃線開頭,並且以雙下劃線結尾的,是特殊變量,特殊變量是可以直接訪問的,不是private變量,所以,不能用__name__、__score__這樣的變數名。有些時候,你會看到以一個底線開頭的實例變數名,例如_name,這樣的實例變數外部是可以存取的,但是,按照約定俗成的規定,當你看到這樣的變數時,意思就是,「雖然我可以被訪問,但是,請把我視為私有變量,不要隨意訪問」。

  8.雙底線開頭的實例變數也不是一定不能從外部存取。不能直接存取__name是因為Python解釋器對外把__name變數改成了_Student__name,所以,仍然可以透過_Student__name來存取__name變數。

9.3繼承

  1.如果一個類似另一個類別的特殊版本,可以使用繼承,一個類別繼承另一個類別它將自動取得另一個類別的所有屬性和方法。原有的類為父類,新類為子類。

  2.子類別繼承父類別所有的屬性和方法,也可以定義自己的屬於和方法。在OOP程式設計中,當我們定義一個class的時候,可以從某個現有的class繼承,新的class稱為子類別(Subclass),而被繼承的class稱為基底類別、父類別或超類(Base class、Super class)。

class Dog(Animal):  #繼承Animal

    pass

9.3.1子類別的方法__init__()

  1.繼承需要給父類別的所有屬性賦值,子類別的__init__()需要父類別施以援手。

  2.且父類別必須在繼承檔案中,在子類別之前。

  3.定義子類別時,必須在括號中指定父類別的名稱。

  4.super()特殊函數,幫助python將父類別和子類別並聯起來。父類也稱超類,super的由來。

9.3.2定義子類別的方法和屬性

  讓一個類別繼承一個類別後。可新增區別子類別和父類別的屬性和方法。

9.3.3重寫父類別

  對應父類別的方法,只有不符合子類別的需要都可以重寫,在子類別中加入新的方法描述子類別的特點。去父類的去其糟怕取其精華。

9.3.4多態

  1.當子類別和父類別都存在相同的方法時,我們說,子類別覆寫了父類別的方法,在程式碼運行的時候,總是會呼叫子類別的方法。這樣,我們就獲得了繼承的另一個好處:多態

  2.所以,在繼承關係中,如果一個實例的資料型別是某個子類,那麼它的資料型別也可以被看做是父類別。但是,反過來就不行。

  3.多態的好處是,當我們需要傳入Dog、Cat、Tortoise…時,我們只需要接收Animal類型就可以了,因為Dog、Cat、Tortoise…都是Animal類型,然後,按照Animal類型進行操作即可。由於Animal類型有run()方法,因此,傳入的任意類型,只要是Animal類別或子類,就會自動呼叫實際類型的run()方法,這就是多態的意思。

  4.對於一個變量,我們只需要知道它是Animal類型,無需確切地知道它的子類型,就可以放心地調用run()方法,而具體調用的run()方法是作用在Animal、Dog、Cat或Tortoise物件上,由運行時該物件的確切類型決定,這就是多態真正的威力:調用方只管調用,不管細節,而當我們新增一種Animal的子類別時,只要確保run()方法寫正確,不用管原來的程式碼是如何呼叫的。這就是著名的「開閉」原則:

  • 對擴展開放:允許新增Animal子類別;

  • 對修改封閉:不需要修改依賴Animal類型的run_twice()等函數。

9.3.5使用__slots__

  為了達到限制的目的,Python允許在定義class的時候,定義一個特殊的__slots__變量,來限制該class實例能新增的屬性。

class Student(object):

    __slots__ = ('name', 'age') # 用tuple定義允許綁定的屬性名稱

  使用__slots__要注意,__slots__定義的屬性僅對目前類別實例起作用,對繼承的子類別是不起作用的。

9.3.6多重繼承

  1.透過多重繼承,一個子類別就可以同時獲得多個父類別的所有功能。

  2.設計類別的繼承關係時,通常,主線都是單一繼承下來的,例如,Ostrich(鴕鳥)繼承自Bird。但是,如果需要「混入」額外的功能,透過多重繼承就可以實現,例如,讓Ostrich除了繼承自Bird外,再同時繼承Runnable。這種設計通常稱之為MixIn。 MixIn的目的是為一個類別增加多個功能,這樣,在設計類別的時候,我們優先考慮透過多重繼承來組合多個MixIn的功能,而不是設計多層次的複雜的繼承關係。

  3.這樣我們就不需要複雜而龐大的繼承鏈,只要選擇組合不同的類別的功能,就可以快速建構出所需的子類別。由於Python允許使用多重繼承,因此,MixIn就是一種常見的設計。只允許單一繼承的語言(如Java)不能使用MixIn的設計。

9.3.7客製化類別

  1.Python的class中還有許多這樣有特殊用途的函數,可以幫助我們客製化類別。

__str__

  定義好__str__()方法,可以回傳一個好看的字串就:

> >> class Student(object):

...     def __init__(self, name):

...         self.name = name

... def __str__(self):

...         return 'Student object (name: %s)' % self.name

...

>>> ; print(Student('Michael'))

Student object (name: Michael)

##  這樣印出來的實例,不但好看,而且容易看出實例內部重要的資料。

  直接敲變數不用print,印出來的實例還是不好看:

>>> s = Student('Michael ')

>>> s

<__main__.Student object at 0x109afb310>

#  這是因為直接顯示變數呼叫的不是__str__(),而是__repr__(),兩者的差異是__str__()傳回使用者看到的字串,而__repr__()傳回程式開發者看到的字串,也就是說,__repr__()是為調試服務的。

  解決方法是再定義一個__repr__()。但通常__str__()和__repr__()程式碼都是一樣的,所以,有個偷懶的寫法:

##__iter__#  如果一個類別想被用於for . .. in循環,類似list或tuple那樣,就必須實作一個__iter__()方法,該方法返回一個迭代對象,然後,Python的for循環就會不斷調用該迭代對象的__next__()方法拿到循環的下一個值,直到遇到StopIteration錯誤時退出循環。
class Student(object):

    def __init__(self, name):

        self.name = name

    s)' % self.name

    __repr__ = __str__

我們以斐波那契數列為例,寫一個Fib類,可以作用於for迴圈:

class Fib(object) :    def __init__(self):

        self.a, self.b = 0, 1 # 初始化兩個計數器a,b

 # #> __iter__(self):

        return self # 實例本身就是迭代對象,故返回自己

 

#   , self.b = self.b, self.a + self.b # 計算下一個值

        if self.a > 100000: # 退出迴

        return self.a # 回傳下一個值

  現在,試試看將Fib實例作用於for迴圈:

  現在,試試看把Fib實例作用於for迴圈:

#>>> for n in Fib():

...     print(n)...
1

1

2

3

#5

...

##46368

75025

#

__getitem__

  Fib實例雖然能作用於for循環,看起來和list有點像,但是,把它當成list來使用還是不行,比如,取第5個元素:

>>> Fib()[5]

Traceback (most recent call last):

  File "

TypeError: 'Fib' object does not support indexing

  要表現得像list那樣依照下標取出元素,需要實作__getitem__()方法:

__getattr__

class Fib(object):

    def __getitem__(self, n):

        a, b = 1, 1

        for x in range(n):

     # return a

#  Python還有另一個機制,那就是寫一個__getattr__()方法,動態回傳一個屬性。當呼叫不存在的屬性時,例如score,Python解釋器會試圖呼叫__getattr__(self, 'score')來嘗試取得屬性,這樣,我們就有機會傳回score的值。已有的屬性,如name,不會在__getattr__中找。

__call__

  1.任何類,只需要定義一個__call__()方法,就可以直接對實例進行呼叫。

  2.透過callable()函數,我們就可以判斷一個物件是否是「可呼叫」物件。

9.3.8枚舉類別

  為這樣的枚舉類型定義一個class類型,然後,每個常數都是class的一個唯一實例。 Python提供了Enum類別來實現這個功能:

from enum import Enum#

9.3.9元類別

type()

  要建立一個class對象,type()函數依序傳入3個參數:

  1. #class的名稱;

  2. 繼承的父類別集合,注意Python支援多重繼承,如果只有一個父類,別忘了tuple的單元素寫法;

  3. class的方法名稱與函數綁定,這裡我們把函數fn綁定到方法名稱hello。

metaclass

  metaclass,直譯為元類,簡單的解釋就是:當我們定義了類別以後,就可以根據這個類別創建出實例,所以:先定義類,然後建立實例。但是如果我們想創建出類別呢?那就必須根據metaclass建立出類,所以:先定義metaclass,然後再建立類別。連接起來就是:先定義metaclass,就可以建立類,最後再建立實例。

__new__()方法接收到的參數依序是:

  1. #目前準備建立的類別的物件;

  2. 類的名字;

  3. 類別繼承的父類別集合;

  4. #類別的方法集合。

9.3.10將實例用作屬性

  使用程式碼模擬實物時,當你添加越來越多的特點和細節是,會發現屬性和方法以及程式碼檔案都越來越長,這時候可以把其中一部分分離,重新組成一個類別。可以將一個大類分成許多小類。

9.3.11模擬實物

  模擬較複雜的實物,需要從較高的邏輯層次考慮。為了編寫效率更高,更簡潔準確的程式碼,可能需要不停的重組類別。

9.4導入類別

  1.隨著不斷對類別的添加,即使很優秀的繼承也會是程式碼變得很長,所以python可以讓你把類別導入模組。並在主程式中導入使用所需的模組。

  2.為自己的每個模組寫文檔字串,說明模組的作用,對內容進行簡要敘述。

  3.從一個模組導入多個類,用逗號隔開,並根據自己的需求建立實例。

  4.也可以導入整個類,並在實例前加上類名,和存取需要的類。

  5.在一個模組中導入另一個模組。

9.5python標準函式庫(模組)

  Python標準函式庫是一組模組,只需要import語句就可以導入使用。

  字典讓你把資訊關聯起來,但不記錄你加入鍵值對的順序,要建立字典並記錄新增鍵值對的順序,可使用模組collections中的orderedDict類別。 OrderedDict的實例和字典一樣,不過記錄了加入鍵值對的新增順序。

  OrderdDict很不錯,兼具列表和字典的特點,有時候很需要。

random模組

  包含各種方式產生隨機數的函數。其中randint()傳回一個位於指定範圍內的整數。

datetime是模組

  datetime模組也包含一個datetime類,透過from datetime import datetime導入的才是datetime這個類別。如果僅匯入import datetime,則必須引用全名datetime.datetime。

  datetime.now()傳回目前日期和時間,其類型是datetime。

常用的第三方函式庫

  還有MySQL的驅動程式:mysql-connector-python,用於科學計算的NumPy函式庫:numpy,用於產生文字的範本工具Jinja2,等等。

  1.urlparse 模組,urlpasrse 模組提供了一些基本功能,用於處理 URL 字串。這些功能包括 urlparse()、 urlunparse()和 urljoin()。

  2.urlparse()將 urlstr 解析成一個 6 元組(prot_sch, net_loc, path, params, query, frag)。前面已 經描述了這裡的每個組件。

  3.urlunparse()的功能與urlpase()完全相反,其將經urlparse()處理的URL 產生urltup 這個6 元組(prot_sch, net_loc, path, params, query, frag),拼接成URL 並返回。

  4.urllib 模組提供了許多函數,可用於從指定 URL 下載數據,同時也可以對字串進行編 碼、解碼工作,以便在 URL 中以正確的形式顯示出來。以下將要介紹的函式包括 urlopen()、 urlretrieve()、quote()、unquote()、quote_plus()、unquote_plus()和 urlencode()。

  5.urlopen()開啟一個給定 URL 字串表示的 Web 連接,並傳回檔案類型的物件。

  6.urlretrieve()不是用來以文件的形式存取並開啟 URL,而是用於下載完整的 HTML,並將另存為文件。

 

9.6類別編碼風格

  熟悉與類別相關的編碼風格,當程式複雜時更應該如此。

  1.類別名稱應採用駝峰命名法,即類別的首字母大寫,不含底線,而實例名稱和模組名稱都首字母小寫,並用底線連接單字。

  2.在每個類別定義後面新增文件字串說明,簡要描述類別的功能作用,並且在每個模組下面都要添加文件字串說明,對模組下的類別可以做什麼進行簡要說明。

  3.用空白行來組織程式碼,但不要濫用,在類別中可用一個空白行分隔方法,用兩個空白行分隔類別。

  4.需要同時導入標準庫中的模組和自己寫的模組時,先寫導入標準庫模組的import語句,用一個空行隔開,在導入自己寫的模組import語句。在包含多個import語句時,可以讓人容易弄清楚程式中各個模組的由來。

Month = Enum('Month', ('Jan' , 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))

以上是Python基礎學習之類的介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn