Python 類的私有成員

你們都知道,一個類的私有成員只能在其所在的類裏可以訪問,而在外部是不行的。好比 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

相關文章
相關標籤/搜索