微信公衆號:碼農充電站pro
我的主頁:https://codeshellme.github.iohtml
那些能用計算機迅速解決的問題,就別用手作了。
—— Tom Duffpython
目錄
git
上一節 咱們介紹了Python 面向對象
的相關概念,咱們已經知道類與對象
是面向對象編程
中很是重要的概念。github
類就是一個模板
,是抽象的。對象是由類建立出來的實例,是具體的。由同一個類建立出來的對象擁有相同的方法
和屬性
,但屬性的值能夠是不一樣的。不一樣的對象是不一樣的實例,互不干擾。shell
以下,是一個最簡單的類,其實是一個空類
,不能作任何事情:編程
class People: pass
在Python 中定義一個類,須要用到class
關鍵字,後邊是類名
,而後是一個冒號:
,而後下一行是類中的代碼,注意要有縮進
。微信
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
的地址。能夠看到不一樣的對象的地址是不一樣的,它們是兩不一樣的實例,互不干擾。this
類中能夠包含屬性
(類中的變量
),建立出來的對象就會擁有相應的屬性,每一個對象的屬性的值能夠不一樣。
建立好對象後,能夠用以下方法給對象添加屬性:
>>> 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__
方法中爲類添加屬性並賦值。
__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
參數,因此在調用該方法的時候,不須要有參數。
私有屬性
普通的屬性,就像上面的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__
,是特殊屬性
,是公有的,可在類的外部訪問
私有方法
私有方法與私有屬性相似,也能夠在方法名的前邊加上雙下劃線__
,來將某個方法變成私有的,通常不須要被外部訪問的方法,應該將其設置爲私有方法
。
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 值 '小麗'
由於這種set
和 get
方法,是由類的開發者提供的,是被開發者控制的。
類的開發者會根據須要,來控制類的使用者如何使用該類,即哪些類的屬性和方法應該被使用者訪問,以及如何被使用者訪問。
如此,類的使用者就不能隨便的訪問類中的屬性,這就達到了封裝
的目的。
(完。)
推薦閱讀:
Python 簡明教程 --- 14,Python 數據結構進階
Python 簡明教程 --- 16,Python 高階函數
Python 簡明教程 --- 17,Python 模塊與包
Python 簡明教程 --- 18,Python 面向對象
歡迎關注做者公衆號,獲取更多技術乾貨。