【python小課堂專欄】python小課堂21 - 面向物件(三)
python小課堂21 - 面向物件(三)
前言
昨天分享了一篇面試最常見的知識點,可以消化消化,今天這篇文章實際上是我昨天晚上加點寫的,為的是與之前的面向物件篇連上,要不後面時間越拖越久,知識的連貫性就斷開了,所以趁熱打鐵,定時推送一篇吧。
PS:可以在通勤(上下班,估計有人不知道通勤是啥意思,這裡解釋下)的路上充分利用碎片時間來學習!
面向物件的可見性
這裡可以先回顧一下之前的示例程式碼,還記得之前女朋友的例子嘛,忘記的話回顧看下喲!
python小課堂18 - 面向物件篇(一)、python小課堂19 - 面向物件篇(二)
1. 成員變數以及方法的公開性
所謂的公開性,就是誰都可以訪問的屬性,比如下面的程式碼,在之前的小課堂程式碼基礎上給女朋友這個類中多新增一個體重的屬性!
class GirlFriend():
# 交過的女朋友個數
total_nums = 0
# 初始化構造方法
def __init__(self, name, age, weight):
self.name = name
self.age = age
self.weight = weight
# 行為,說出自己的特徵
def say_feature(self):
print (f'我的姓名:{self.name}')
print(f'我的年齡:{self.age}')
girlFriend = GirlFriend('女兒國公主', 18, 90)
girlFriend.say_feature()
print(f'女朋友的體重:{girlFriend.weight}斤')
結果輸出:
>>> 我的姓名:女兒國公主
>>> 我的年齡:18
>>> 女朋友的體重:90斤
90斤是不是非常輕了,這算是苗條了吧!
然而…公開性的意義就是我是老大,我說了算,我完全可以修改物件初始化時女票的體重,我要給她修改成一個大胖紙。。。來看下:
class GirlFriend():
# 交過的女朋友個數
total_nums = 0
# 初始化構造方法
def __init__(self, name, age, weight):
self.name = name
self.age = age
self.weight = weight
# 行為,說出自己的特徵
def say_feature(self):
print(f'我的姓名:{self.name}')
print(f'我的年齡:{self.age}')
girlFriend = GirlFriend('女兒國公主', 18, 90)
girlFriend.weight = 300
print(f'女朋友的體重:{girlFriend.weight}斤')
結果輸出:
>>> 女朋友的體重:300斤
O(∩_∩)O哈哈~,變成胖紙了呢!這就是所謂的物件公開性,我們可以通過例項化後的引用來直接訪問物件的變數,方法。甚至可以修改變數的值!
2. 方法的私有性
現實世界處處皆有平衡性,有陰即有陽,有公開即有私有!大家都知道,女生的體重一直是比較隱私的資料了,不可能讓我們這麼隨意的修改,所以呢,我們將其置為私有變數,外部就無法將其修改了,同樣的物件中的方法也是一個道理!先來看下物件的私有方法,我們將與女生體重無關的say_feature
變為私有方法,只需要在它前面加上__即可:
class GirlFriend():
# 交過的女朋友個數
total_nums = 0
# 初始化構造方法
def __init__(self, name, age, weight):
self.name = name
self.age = age
self.__weight = weight
# 行為,說出自己的特徵
def __say_feature(self):
print(f'我的姓名:{self.name}')
print(f'我的年齡:{self.age}')
girlFriend = GirlFriend('女兒國公主', 18, 90)
girlFriend.say_feature()
可以看到報錯了,說找不到這個say_feature
屬性,因為已經將其前面加上了雙下劃線,那我就改下程式碼,試試訪問__say_feature
呢?
依然可以看到報錯,因為python的內建將方法前面帶有雙下劃判定為私有方法,有人可能回想之前說過的__init__,前面也帶有雙下劃線,為毛沒有被認定為私有方法呢?因為凡是__xx__這樣構造的樣式,都是python的內建函式,細微之差就是人家還有後面的雙劃線!
3. 成員變數的私有性
為什麼我把成員變數的私有性單獨提出來了一個小點,因為變數的私有性還與方法有點那麼不一樣!如下,將weight變數前面加上__weight
:
class GirlFriend():
# 交過的女朋友個數
total_nums = 0
# 初始化構造方法
def __init__(self, name, age, weight):
self.name = name
self.age = age
self.__weight = weight
# 行為,說出自己的特徵
def __say_feature(self):
print(f'我的姓名:{self.name}')
print(f'我的年齡:{self.age}')
girlFriend = GirlFriend('女兒國公主', 18, 90)
print(f'女朋友的體重:{girlFriend.weight}斤')
結果,可以看到例項呼叫的體重已經報錯了:
在來試試通過下劃線的形式修改並且訪問呢?畢竟已經將例項變數weight重名為了__weight:
神奇的發現,居然可以修改,並且還可以訪問,不是已經改為私有變量了嘛。。。其實這就要跟下面的講到的python特性有關了,請繼續往下看…
關於私有化的進階話題
python是一種動態語言,所謂的動態語言,這裡來舉個例子,比如咱們在python中建立變數時,是無需宣告變數明確的型別的,而可以直接用a = 1
來將整型的數字1賦值給變數a。在其它的語言中,比如Java,是需要在a的前面宣告變數型別的,例如 int a = 1;
這樣的寫法。而在python的面向物件特性中,正因為這種動態化影響了私有化的理解,這麼說可能不太明白,還是下面用剛才的示例來解釋下,只需要將上述程式碼修改一下順序,將列印的結果與修改的程式碼順序互換,即可得到答案:
發現報錯了!實際上,由於python的動態性,將 girlFriend.__weight = 300
這行程式碼動態賦值給了girlFriend這個例項名為__weight
的新屬性,還記得上一節提到的__dict__
嗎?來驗證看下女票這個例項物件究竟有哪些屬性:
注意到後兩個引數,實際上我們第一次賦給女票體重的90斤,在python例項物件中叫_GirlFriend__weight
,而__weight
賦值的300斤則是新增的屬性罷了!
相信熱于思考的同學絕對會再去嘗試,是不是如果訪問_GirlFriend__weight
,並且修改它,就可以實際修改了所謂的私有變數呢?如果你是這麼想的,恭喜你,想的一點也沒有錯!可以看到下面的實驗:
結論:python實際上是沒有所謂真正的私有變數,只要你想訪問,就一定可以訪問到,只要你想修改,那麼一定可以修改,就是這麼神奇!python對於私有變數實際上耍了一個小聰明,就是將__xxx的變數修改了名字,表面上不讓你訪問到而已罷了!~
總結
本篇介紹了python面向物件的成員的可見性,對於物件的私有化來說,可以遮蔽那些外界想主動修改的變數或者方法的操作,禁止他們訪問與修改。
回顧下前面的兩章面向物件,主要講了面向物件的類變數、例項變數;類的例項方法、類方法、靜態方法和建構函式。本章介紹了類的成員可見性。寫到這裡,不知不覺已經這麼多了,後面看來還得在延長至少一章介紹面向物件的三大特性!敬請期待…
至此完!
有想交流溝通python相關知識的同學,歡迎關注公號: