1. 程式人生 > >Python 簡明教程 --- 19,Python 類與物件

Python 簡明教程 --- 19,Python 類與物件

> **微信公眾號:碼農充電站pro** > **個人主頁:** > **那些能用計算機迅速解決的問題,就別用手做了。** > —— Tom Duff **目錄** ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200625172328301.png?#pic_center) [上一節](https://www.cnblogs.com/codeshell/p/13193851.html) 我們介紹了`Python 面向物件`的相關概念,我們已經知道`類與物件`是`面向物件程式設計`中非常重要的概念。 類就是一個`模板`,是抽象的。物件是由類創建出來的例項,是具體的。由同一個類創建出來的物件擁有相同的`方法`和`屬性`,但屬性的值可以是不同的。不同的物件是不同的例項,互不干擾。 ### 1,類的定義 如下,是一個最簡單的類,實際上是一個`空類`,不能做任何事情: ```python class People: pass ``` 在Python 中定義一個類,需要用到`class` 關鍵字,後邊是`類名`,然後是一個`冒號:`,然後下一行是類中的程式碼,注意要有`縮排`。 ### 2,建立物件 `People` 雖然是一個`空類`,但依然可以建立物件,建立一個物件的語法為: ```python 物件名 = 類名(引數列表) ``` 引數列表是跟`__init__` 構造方法相匹配的,如果沒有編寫`__init__` 方法,建立物件時,就不需要寫引數,如下: ```shell >
>> p = People() >>> p <__main__.People object at 0x7fd30e60be80> >>> >>> p1 = People() >>> p1 <__main__.People object at 0x7fd30e60be48> ``` `p` 和 `p1` 都是`People`類的物件。`0x7fd30e60be80` 是`p` 的地址,`0x7fd30e60be48` 是`p1` 的地址。可以看到不同的物件的地址是不同的,它們是兩不同的例項,互不干擾。 ### 3,屬性 類中可以包含`屬性`(`類中的變數`),創建出來的物件就會擁有相應的屬性,每個物件的屬性的值可以不同。 建立好物件後,可以用如下方法給物件新增屬性: ```shell >>> p = People() >>> p.name = '小明' # 新增 name 屬性 >>> p.sex = '男' # 新增 sex 屬性 >>> p.name # 訪問物件的屬性 '小明' >>> p.sex # 訪問物件的屬性 '男' ``` 雖然在技術上可以這樣做,但是一般情況下,我們並不這樣為物件新增屬性,這樣會破壞類的`封裝性`,使得程式碼混亂,不利於維護。 當訪問一個不存在的屬性時,會出現異常: ```shell >>> p.job # 一個不存在的屬性 Traceback (most recent call last): File "", line 1, in AttributeError: 'People' object has no attribute 'job' ``` 我們一般會在`__init__` 方法中為類新增屬性並賦值。 ### 4,**`__init__` 方法** 在Python 的類中,以雙下劃線`__`開頭和結尾的方法,被稱為`魔法方法`,每個魔法方法都有特定的含義。Python 為我們規定了一些魔法方法,讓我們自己實現這些方法。 `__init__` 方法叫做`構造方法`,用來初始化物件。Python 直譯器會在生成`物件`時,自動執行構造方法,而無需使用者顯示呼叫。 `__init__` 方法不需要有返回值。 類中的所有`例項方法` 方法,都至少有一個引數,就是`self`。Python 中的`self ` 相當於C++ 和Java 中的`this` 指標,都是代表當前物件。只是Python 中的`self` 需要顯示寫在方法的第一個引數,而`this` 指標則不需要寫在方法引數中。 構造方法一般用於初始化物件的一些屬性,建構函式可以不寫,也可以只有一個`self` 引數。 當建構函式只有一個`self` 引數時,建立該類的物件時,不需要新增引數。當建構函式除了`self` 引數還有其它引數時,建立該類的物件時,則需要新增相匹配的引數。 比如,我們定義一個`People` 類,它有三個屬性,分別是`name`,`sex`,`age`: ```python class People: def __init__(self, name, sex, age): self.name = name self.sex = sex self.age = age print('執行了 __init__ 方法') def print_info(self): print('people:%s sex:%s age:%s' % ( self.name, self.sex, self.age)) ``` 在這個`People` 類中除了有一個`__init__` 方法外,還有一個`print_info` 方法,每個方法中的都有`self` 引數,並且是第一個引數,`self` 代表當前物件。 在建立該類的物件時,需要傳遞匹配的引數(`self` 引數不用傳遞): ```shell >>> p = People('小明', '男', 18) 執行了 __init__ 方法 >>> p >>> p.print_info() people:小明 sex:男 age:18 >>> >>> p1 = People('小美', '女', 18) 執行了 __init__ 方法 >>> p1 >>> p1.print_info() people:小美 sex:女 age:18 ``` 可以看到,在建立`p` 和`p1` 物件時,字串`執行了 __init__ 方法` 被列印了出來,而我們並沒有顯示呼叫該方法,說明`__init__` 方法被預設執行了。 物件`p` 和`p1` 是兩個不同的物件,擁有相同的屬性和方法,但是屬性值是不一樣的。兩個物件互不干擾,物件`p` 的地址為`0x7feb6276bda0`,`p1` 的地址是`0x7fd54352be48`。 執行程式碼`p.print_info()`,是呼叫`p` 物件的`print_info()` 方法,因為,在定義該方法的時候,只有一個`self` 引數,所以在呼叫該方法的時候,不需要有引數。 ### 5,私有屬性和方法 **私有屬性** 普通的屬性,就像上面的`name`,`sex`和`age` 屬性,都是`公有屬性`,在類的外部都可以被任意的訪問,就是可以用`物件.屬性名`的方式來訪問屬性,如下: ```shell >>> p = People('小明', '男', 18) 執行了 __init__ 方法 >>> p.name # 訪問屬性 '小明' >>> p.name = '小麗' # 修改屬性 >>> p.name # 訪問屬性 '小麗' ``` 這樣就破壞了資料的`封裝性`,這種訪問方式是不可控(會不受限制的被任意訪問)的,不利於程式碼的維護,不符合面向物件的程式設計規範。 所以,通常我們會將類中的屬性,改為`私有屬性`,就是不能以`物件.屬性名` 這樣的方式訪問類屬性。 在Python 中,通過在屬性名的前邊新增雙下劃線`__`,來將`公有屬性`變為`私有屬性`,如下: ```python #! /usr/bin/env python3 class People: def __init__(self, name, sex, age): self.__name = name # 兩個下劃線 self.__sex = sex # 兩個下劃線 self._age = age # 一個下劃線 print('執行了 __init__ 方法') def print_info(self): print('people:%s sex:%s age:%s' % ( self.__name, self.__sex, self._age)) ``` 這樣就無法通過`物件.屬性名`的方式來訪問屬性了,如下: ```shell >>> p = People('小美', '女', 18) 執行了 __init__ 方法 >>> p.__name # 出現異常 Traceback (most recent call last): File "", line 1, in AttributeError: 'People' object has no attribute '__name' ``` 但是,Python 中這種`私有屬性`的方式,並不是真正的私有屬性,Python 只是將`__name` 轉換為了`_People__name`,即是在`__name` 的前邊加上了`_類名`(`_People`),我們依然可以這樣訪問`__name` 屬性: ```shell >>> p._People__name '小美' ``` 但我們並不提倡這種方式,這會讓程式碼變得混亂難懂。 可以注意到,`People` 類中的`_age` 屬性是以單下劃線開頭的,這種以單下劃線開頭的屬性是可以在類的外部被訪問的: ```shell >>> p._age 18 ``` 但是根據Python 規範,以單下劃線開頭的屬性,也被認為是`私有屬性`,也不應該在類的外部訪問(雖然在技術上是可以訪問的)。 > 注意:以雙下劃線`__` 開頭且結尾的屬性`__xxx__`,是`特殊屬性`,是公有的,可在類的外部訪問 **私有方法** 私有方法與私有屬性類似,也可以在方法名的前邊加上雙下劃線`__`,來將某個方法變成私有的,一般不需要被外部訪問的方法,應該將其設定為`私有方法`。 ### 6,`set` 和 `get` 方法 為了資料的`封裝性`,我們不應該直接在類的外部以`物件.屬性名`的方式訪問屬性,那麼如果我們需要訪問類的屬性該怎麼辦呢? 這時我們需要為每個私有屬性都提供兩個方法: - set 方法:用於設定屬性的值 - get 方法:用於訪問屬性的值 為了減少程式碼量,這裡只為`__name` 屬性設定了這兩個方法,程式碼如下: ```python #! /usr/bin/env python3 class People: def __init__(self, name, sex, age): self.__name = name self.__sex = sex self._age = age print('執行了 __init__ 方法') def print_info(self): print('people:%s sex:%s age:%s' % ( self.__name, self.__sex, self._age)) # set 和 get 方法 def set_name(self, name): self.__name = name def get_name(self): return self.__name ``` 使用者可以這樣設定和訪問類的屬性: ```shell >>> from People import People >>> p = People('小美', '女', 18) 執行了 __init__ 方法 >>> p.get_name() # 獲取 name 值 '小美' >>> p.set_name('小麗') # 設定新的值 >>> p.get_name() # 再次獲取name 值 '小麗' ``` (完。) --- **推薦閱讀:** [Python 簡明教程 --- 14,Python 資料結構進階](https://www.cnblogs.com/codeshell/p/13040449.html) [Python 簡明教程 --- 15,Python 函式](https://www.cnblogs.com/codeshell/p/13040458.html) [Python 簡明教程 --- 16,Python 高階函式](https://www.cnblogs.com/codeshell/p/13158903.html) [Python 簡明教程 --- 17,Python 模組與包](https://www.cnblogs.com/codeshell/p/13158924.html) [Python 簡明教程 --- 18,Python 面向物件](https://www.cnblogs.com/codeshell/p/13193851.html) --- 歡迎關注作者公眾號,獲取更多技術乾貨。 ![碼農充電站pro](https://img-blog.csdnimg.cn/20200505082843773.png?#pic