iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 16
1
Software Development

python 自學系列 第 16

python day16 (private、underscore)

  • 分享至 

  • xImage
  •  

python 並沒有 private 這種東西,只能透過命名的方式希望不要讓別人存取.而命名方式就是在變數或方法前面加上_

>>> class Animal:
...  age = 0
...  def __init__(self,name):
...   self.name = name
...  def _count_age(self,age):
...   return age * 10
...  def add_age(self,new_age):
...   Animal.age = self._count_age(new_age)
...  def print_age(self):
...   print(Animal.age)
...
>>> a1 = Animal('Cat')
>>> a1.add_age(5)
>>> a1.print_age()
50

還是可以呼叫得到.

>>> a1._count_age(3)
30

寫一隻 my_caculate.py 定義兩個 function :

def add(a,b):
 return a + b

def _sum(a,b):
 return a + b

把 my_caculate 模組 import 進來,python 會避開_開頭的 function,所以_sum不會被 import 進來.

>>> from my_caculate import *
>>> add(1,2)
3
>>> _sum(2,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name '_sum' is not defined

但如果使用下面方式 import 就可以呼叫得到.

>>> from my_caculate import _sum
>>> _sum(2,3)
5

underscore 目前已經知道有__名稱___名稱,另外還有兩種是名稱___名稱共 4 種寫法.

名稱_
主要是用來避免與 built-in 名稱相同,比如說 puthon 已經有定義 list 這名稱,但如果還是很想用 list 這名稱當作自定義的變數時,就可以在 list 後面加上 underscore 變成 list_.

__名稱
在遇到 class 與 subclass 都使用到相同的變數名稱時,會發生命名碰撞的問題,如下當子類別使用父類別的方法時,由於 self 是子類別的 instance 所以 get_sum function 裡的 self.sum 是子類別 Calc2 的實體變數 sumn 所以 2 + 5 答案會是 7.

>>> class Calc1:
...  sum = 10
...  def get_sum(self):
...   return self.sum
...
>>> class Calc2(Calc1):
...  def add_sum(self,num):
...   self.sum = 2
...   return self.get_sum() + num
...
>>> c1 = Calc1()
>>> c1.sum
10
>>> c2 = Calc2()
>>> c2.add_sum(5)
7
>>> c2.sum
2

其實上面的案例用物件導向的方式思考感覺是蠻合理的,因為使用的是 Calc2 所以計算時當然是希望用的是 Calc2 的 sum.但如果改成使用__sum這時候 Calc1 的__sum跟 Calc2 的__sum就不會發生命名碰撞了.既然不會發生碰撞所以當你呼叫 Calc1 的 get_sum 其實 Calc1 的__sum已經變成了_Calc1__sum,而 Calc2 的__sum變成了_Calc2__sum,所以各自類別裡的 __sum 不會產生衝突.

>>> class Calc1:
...  __sum = 10
...  def get_sum(self):
...   return self.__sum
...
>>> class Calc2(Calc1):
...  def add_sum(self,num):
...   self.__sum = 2
...   return self.get_sum() + num
...

既然__sum已經改變所以用.__sum當然找不到這屬性.

>>> c1 = Calc1()
>>> c1.__sum
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Calc1' object has no attribute '__sum'

必須使用下面的方式存取(_類別名稱__名稱).

>>> c1._Calc1__sum
10

這時候呼叫可以發現self.get_sum()取得就是 Calc1 的__sum,答案就會是 10 + 5.

>>> c2 = Calc2()
>>> c2.add_sum(5)
15
>>> c2._Calc2__sum
2

最後整理一下 :

  1. python 沒有真正的 private,只能透過命名方式來表示,但還是都有辦法存取得到.
  2. python 的 underscore 主要有四種,__名稱___名稱名稱___名稱

今天為了介紹上面兩個觀念,範例其實還用到了模組跟子類別,後面的篇章再繼續介紹.


上一篇
python day15 (classes)
下一篇
python day17 (module、package)
系列文
python 自學30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
山姆大叔
iT邦新手 4 級 ‧ 2019-10-01 15:13:37

長知識了...原來python還會避開_開頭的方法阿!

我要留言

立即登入留言