微信公眾號:碼農充電站pro
個人主頁:https://codeshellme.github.io
那些能用計算機迅速解決的問題,就別用手做了。
—— Tom Duff
目錄
上一節 我們介紹了Python 物件導向
的相關概念,我們已經知道類與物件
是物件導向程式設計
中非常重要的概念。
類就是一個模板
,是抽象的。物件是由類建立出來的例項,是具體的。由同一個類建立出來的物件擁有相同的方法
和屬性
,但屬性的值可以是不同的。不同的物件是不同的例項,互不干擾。
1,類的定義
如下,是一個最簡單的類,實際上是一個空類
,不能做任何事情:
class People:
pass
在Python 中定義一個類,需要用到class
關鍵字,後邊是類名
,然後是一個冒號:
,然後下一行是類中的程式碼,注意要有縮排
。
2,建立物件
People
雖然是一個空類
,但依然可以建立物件,建立一個物件的語法為:
物件名 = 類名(引數列表)
引數列表是跟__init__
構造方法相匹配的,如果沒有編寫__init__
方法,建立物件時,就不需要寫引數,如下:
>>> p = People()
>>> p
<__main__.People object at 0x7fd30e60be80>
>>>
>>> p1 = People()
>>> p1
<__main__.People object at 0x7fd30e60be48>
p
和 p1
都是People
類的物件。0x7fd30e60be80
是p
的地址,0x7fd30e60be48
是p1
的地址。可以看到不同的物件的地址是不同的,它們是兩不同的例項,互不干擾。
3,屬性
類中可以包含屬性
(類中的變數
),建立出來的物件就會擁有相應的屬性,每個物件的屬性的值可以不同。
建立好物件後,可以用如下方法給物件新增屬性:
>>> p = People()
>>> p.name = '小明' # 新增 name 屬性
>>> p.sex = '男' # 新增 sex 屬性
>>> p.name # 訪問物件的屬性
'小明'
>>> p.sex # 訪問物件的屬性
'男'
雖然在技術上可以這樣做,但是一般情況下,我們並不這樣為物件新增屬性,這樣會破壞類的封裝性
,使得程式碼混亂,不利於維護。
當訪問一個不存在的屬性時,會出現異常:
>>> p.job # 一個不存在的屬性
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
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
:
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
引數不用傳遞):
>>> p = People('小明', '男', 18)
執行了 __init__ 方法
>>> p
<People.People object at 0x7feb6276bda0>
>>> p.print_info()
people:小明 sex:男 age:18
>>>
>>> p1 = People('小美', '女', 18)
執行了 __init__ 方法
>>> p1
<People.People object at 0x7fd54352be48>
>>> 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
屬性,都是公有屬性
,在類的外部都可以被任意的訪問,就是可以用物件.屬性名
的方式來訪問屬性,如下:
>>> p = People('小明', '男', 18)
執行了 __init__ 方法
>>> p.name # 訪問屬性
'小明'
>>> p.name = '小麗' # 修改屬性
>>> p.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))
這樣就無法通過物件.屬性名
的方式來訪問屬性了,如下:
>>> p = People('小美', '女', 18)
執行了 __init__ 方法
>>> p.__name # 出現異常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'People' object has no attribute '__name'
但是,Python 中這種私有屬性
的方式,並不是真正的私有屬性,Python 只是將__name
轉換為了_People__name
,即是在__name
的前邊加上了_類名
(_People
),我們依然可以這樣訪問__name
屬性:
>>> p._People__name
'小美'
但我們並不提倡這種方式,這會讓程式碼變得混亂難懂。
可以注意到,People
類中的_age
屬性是以單下劃線開頭的,這種以單下劃線開頭的屬性是可以在類的外部被訪問的:
>>> p._age
18
但是根據Python 規範,以單下劃線開頭的屬性,也被認為是私有屬性
,也不應該在類的外部訪問(雖然在技術上是可以訪問的)。
注意:以雙下劃線
__
開頭且結尾的屬性__xxx__
,是特殊屬性
,是公有的,可在類的外部訪問
私有方法
私有方法與私有屬性類似,也可以在方法名的前邊加上雙下劃線__
,來將某個方法變成私有的,一般不需要被外部訪問的方法,應該將其設定為私有方法
。
6,set
和 get
方法
為了資料的封裝性
,我們不應該直接在類的外部以物件.屬性名
的方式訪問屬性,那麼如果我們需要訪問類的屬性該怎麼辦呢?
這時我們需要為每個私有屬性都提供兩個方法:
- set 方法:用於設定屬性的值
- get 方法:用於訪問屬性的值
為了減少程式碼量,這裡只為__name
屬性設定了這兩個方法,程式碼如下:
#! /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
使用者可以這樣設定和訪問類的屬性:
>>> from People import People
>>> p = People('小美', '女', 18)
執行了 __init__ 方法
>>> p.get_name() # 獲取 name 值
'小美'
>>> p.set_name('小麗') # 設定新的值
>>> p.get_name() # 再次獲取name 值
'小麗'
(完。)
推薦閱讀:
Python 簡明教程 --- 14,Python 資料結構進階
Python 簡明教程 --- 16,Python 高階函式
Python 簡明教程 --- 17,Python 模組與包
Python 簡明教程 --- 18,Python 物件導向
歡迎關注作者公眾號,獲取更多技術乾貨。