你們都知道,一個類的私有成員只能在其所在的類裏可以訪問,而在外部是不行的。好比 C++ 或者 Java 的 private 關鍵字就是用來聲明類的私有成員的,若是一個屬性或者方法被 private 聲明,那麼這個成員就只能在類裏面才能直接使用,這樣作的目的是爲了封裝。和不少面向對象的語言同樣,Python 也支持類的私有成員的使用,不過有些差異。後端
class T:
__v = 'I am a private variable'
v = 'I am a public variable'
def get_private_v(self):
return self.__v
def get_public_v(self):
return self.v
複製代碼
而後在終端下測試bash
>>> T.v
'I am a public variable'
>>> T.__v
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'T' has no attribute '__v'
>>> T().get_private_v()
'I am a private variable'
>>> T().get_public_v()
'I am a public variable'
複製代碼
上面的結果與預期相符,可是測試
>>> T._T__v
'I am a private variable'
複製代碼
這就有些神奇了。原來 Python 裏面並無真正的私有成員,只不過是在編譯的時候直接將成員 __variable
替換成了 _classname__variable
。解釋器在碰到 self.__v
的時候直接將其解釋爲 self._T__v
,這樣一來,在類外面就不能經過 T().__v
的方式訪問了。這在必定程度上體現的私有成員的意義,不過這就無法阻止外部經過 T()._T__v
訪問私有成員了。ui
不過要注意, exec()、eval()、getattr()、setattr()、delattr() 在類裏面沒法經過 self.__variable
的方式訪問私有變量spa
class A:
__a = 1
a = 2
def get_private_a(self):
return eval('self.__a')
def get_public_a(self):
return eval('self.a')
def get_private_a2(self):
return eval('self._A__a')
# 測試
>>> A().get_private_a()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/kevinbai/Downloads/test/test.py", line 16, in get_private_a
return eval('self.__a')
File "<string>", line 1, in <module>
AttributeError: 'A' object has no attribute '__a'
>>> A().get_public_a()
2
>>> A().get_private_a2()
1
複製代碼
個人理解是,在使用上面的幾個方法訪問成員變量時,解釋器不會執行將 self.__a
解釋爲 self._A__a
的步驟,因此 A().get_private_a()
方法執行到 eval('self.__a')
時會報對象屬性不存在的錯誤。可是,若是經過替換後的變量來訪問,就不會有問題。code
簡單來講, Python 中私有成員其實只是在編譯時經過名字的替換來實現的。當在類裏訪問相應的成員時,解釋器會作轉換,可是使用 eval() 等方法時,解釋器不會執行這個步驟。對象
本文首發於公衆號「小小後端」。get