python學習筆記013 模組中的私有屬性

2021-09-08 05:05:29 字數 4704 閱讀 4929

在python中,沒有類似private之類的關鍵字來宣告私有方法或屬性。若要宣告其私有屬性,語法規則為:

屬性前加雙下劃線,屬性後不加(雙)下劃線,如將屬性name私有化,則 __name

即可。(實際上,屬性前加單下劃線,屬性後不加下劃線也可以 _name )

1)以乙個下劃線開頭的識別符號(_***),不能訪問的方法或屬性,但可通過類提供的介面進行訪問, 不會被語句 from module import * 語句載入。

單下劃線開頭的方式或屬性:弱」內部使用「標識,如:」from m import *」,將不匯入所有以下劃線開頭的物件,包括包、模組、成員

只是為了避免與python關鍵字的命名衝突

2)以兩個下劃線開頭的識別符號(__***),不能被外部訪問的方法或屬性,不會被語句 from module import * 語句載入,外部訪問時會報錯。

雙下劃線開頭的方法或屬性:模組內的成員,表示私有成員,外部無法直接呼叫 

def

hello1():

pass

def_hello2():

pass

def__hello3

():

pass

name1 = "

name1

"_name2 = "

name2

"__name3 = "

name3

"print("

該模組已被載入!

")

在互動模式下執行

>>> from test import *該模組已被載入!

>>>dir()['

__builtins__

', '

__doc__

', '

__loader__

', '

__name__

', '

__package__

', '

__spec__

', '

hello1

', '

name1

']

可知,僅載入了 hello1 方法、 name1 屬性

實際上,這種方式並不是真正私有,而是」偽私有「,也即偽私有屬性;

它是通過變數名壓縮(mangling)來實現變數名區域性化。變數名壓縮的規則:在初始的變數名頭部加乙個下劃線,再加上類的名稱,最後是初始變數名的名稱。

class

action(object):

def__func

(self):

pass

if__name__ == '

__main__':

print(action.__dict__)

類 action 中有私有方法 __func

。**執行

通過類的__dict__屬性類class action 的所有屬性列印出來,發現原定義的私有屬性(方法)__func不存在,而是以_action__func的形式存在於類中,也即方法__func變數名被壓縮;,會自動進行擴充套件,從而包含所在類的名稱。我們可以通過_action__func來呼叫該類中的方法,這就是所謂的偽私有屬性

通過修改呼叫形式就可以實現私有屬性的外部呼叫:

class

action(object):

def__func

(self):

print("

__func私有方法被呼叫")

if__name__ == '

__main__':

a =action()

a._action__func()

print("

----------------------")

b =action()

b.__func()

執行

__func私有方法被呼叫

----------------------traceback (most recent call last):

file

"test.py

", line 10, in

b.__func

()attributeerror:

'action

' object has no attribute '

__func

'

python之所以支援變數名壓縮(mangling),讓類內部某些屬性和函式區域性化,使方法或屬性無法在外部訪問。這是因為私有屬性被自動擴充套件為含有所在類的名稱。

__membername

被系統替換成了 _classname__membername 外部使用原來的私有成員的名字時,會提示找不到。

偽私有屬性是為了緩和與例項屬性儲存方式有關的問題。在python中,所有例項的屬性都會在類樹底部的單個例項物件中。

在python的類方法中,每當方法賦值self的屬性時(如self.attr = value),就會在該例項內修改或建立該屬性(繼承搜尋只發生在引用時,而不是賦值時)。

即使在這個層次中有多個相同的類賦值屬性,也是如此。因此有可能發生衝突。

偽私有屬性在較大的框架和工具中非常有用,既避免引入可能在類樹中某處偶然隱藏定義的新的方法名,也可以減少內部方法被樹的較低處的名稱替代的機會。

如果乙個屬性或方法傾向於只在乙個類中使用,在前面使用雙下劃線,一確保不受到繼承樹中其它名稱的干擾,尤其是在多繼承的環境中。

簡而言之:使用偽私有屬性可以解決變數名相互覆蓋問題,也即  使用偽私有屬性是為了避免在類樹中,多個類賦值相同的屬性引發衝突問題。

示例

假設有兩個類,c1 和 c2,他們都有相同的屬性x。

類c1

class

c1():

defmeth1(self):

self.x = '

hello world

'def

meth2(self):

print

(self.x)

c1 =c1()

c1.meth1()

c1.meth2()

類c2

class

c2():

defmeth3(self):

self.x = '

hello python

'def

meth4(self):

print

(self.x)

c2 =c2()

c2.meth3()

c2.meth4()

類c1和c2在單獨呼叫時,均能符合預期地輸出

呼叫meth2方法時,列印meth1的賦值結果;

呼叫meth4方法時,列印meth3的賦值結果。

此時增加乙個新的類c3,繼承自c1、c2(多重繼承): 

class

c1():

defmeth1(self):

self.x = '

hello world

'def

meth2(self):

print

(self.x)

class

c2():

defmeth3(self):

self.x = '

hello python

'def

meth4(self):

print

(self.x)

class

c3(c1, c2):

pass

c3 =c3()

c3.meth1()

c3.meth3()

c3.meth2()

c3.meth4()

從執行結果可以看出,每次 print(self.x)的內容,取決於 self.x 最後一次賦值的內容。存在賦值覆蓋問題

hello python

hello python

在使用偽私有屬性後可以解決變數名self.x相互覆蓋的問題(因為self.__x 被壓縮成了 self._c1__x 和 self._c2__x,變數名不同,不會互相覆蓋):

class

c1():

defmeth1(self):

self.

__x = '

hello world

'def

meth2(self):

print(self.__x

)class

c2():

defmeth3(self):

self.

__x = '

hello python

'def

meth4(self):

print(self.__x

)class

c3(c1, c2):

pass

c3 =c3()

c3.meth1()

c3.meth3()

c3.meth2()

c3.meth4()

執行結果符合c1的設計初衷:呼叫meth2時應該列印出meth1的賦值結果:

hello world

hello python

參考:python的偽私有屬性

python高階特性:私有屬性

python學習筆記013 內建函式dir

dir 函式 不帶引數時,返回當前範圍內的變數 方法和定義的型別列表 帶引數時,返回引數的屬性 方法列表。如果引數包含方法 dir 該方法將被呼叫。如果引數不包含 dir 該方法將最大限度地收集引數資訊。或 1.如果沒有引數呼叫,則返回當前作用域的所有變數的列表 2.如果給定乙個物件作為引數,則返回...

Python學習筆記 模組

模組,用一砣 實現了某個功能的 集合。類似於函式式程式設計和面向過程程式設計,函式式程式設計則完成乙個功能,其他 用來呼叫即可,提供了 的重用性和 間的耦合。而對於乙個複雜的功能來,可能需要多個函式才能完成 函式又可以在不同的.py檔案中 n個 py 檔案組成的 集合就稱為模組。如 os 是系統相關...

python學習筆記 模組

pickle模組實現了基本的資料序列和反序列化。通過pickle模組的序列化操作我們能夠將程式中執行的物件資訊儲存到檔案中去,永久儲存。通過pickle模組的反序列化操作,我們能夠從檔案中建立上一次程式儲存的物件。基本介面 pickle.dump obj,file,protocol 讀取方式開啟檔案...