2010-01-14 103 views
52

如何在Python中使方法和數據成員保持私有狀態?或者Python不支持私有成員?Python中的私人成員

+0

大家很奇怪:吉多·範羅蘇姆剛纔解釋缺乏「真正的」私有變量在Python:https://plus.google.com/115212051037621986145/posts/7wpbQTPRWft一言以蔽之:因爲實用性擊敗純度 – Johannes 2011-08-22 18:55:32

回答

59

9.6. Private Variables

「私有」實例變量 不能從除內部 對象進行訪問,不要在Python存在。 但是,有一個約定是 ,後面是大多數Python代碼:名稱爲 的前綴爲下劃線(例如 _spam)應被視爲API的非公開部分(它是否爲 是函數,方法或數據 成員)。它應該被認爲是 的實施細節,並受 更改,恕不另行通知。

由於存在一個有效的用例爲 類私有成員(即,以避免與由子類定義名稱 名 名稱衝突),存在對這樣一種機制 支持有限, 叫名字粉碎。 (至多一個 結尾下劃線至少兩個 前導下劃線)的形式__spam的任何標識符 在文字上 與_classname__spam,其中 classname即當前的類名 剝去前導下劃線(一個或多個)所取代。 只要在類的定義中出現 ,就不考慮 到 標識符的語法位置。

所以,for example

class Test: 
    def __private_symbol(self): 
     pass 
    def normal_symbol(self): 
     pass 

print dir(Test) 

將輸出:

['_Test__private_symbol', 
'__doc__', 
'__module__', 
'normal_symbol'] 

__private_symbol應該算是一個私有方法,但它仍然會通過_Test__private_symbol訪問。

+1

但是如果我不希望我的客戶使用某些方法?(即客戶無需擔心的方法,如用於向公共方法提供服務的方法,但是無用的公開方法) – appusajeev 2010-01-14 13:17:25

+6

@appusajeev:don沒有記錄他們。如果他們使用它們,這是他們的問題。 – SilentGhost 2010-01-14 13:21:15

+4

以一個或多個下劃線開頭的方法不會被記錄,也就是說,當在解釋器中的類上使用'help()'時,它們不會顯示出來。您的客戶仍然可以在技術上使用它們,但如果他們這樣做,這是他們自己的問題。 – mipadi 2010-01-14 13:34:52

7

如果一個Python函數的名稱, 類方法,或屬性與 開始(但不是結束)兩大 下劃線,它是私有的;一切 其他是公開的。 Python沒有受保護類方法的概念 (僅在其自己的類和 類中可訪問 )。班級方法要麼是 私人(只能在他們自己的 班級訪問)或公共(可從任何地方從 訪問)。

Dive Into Python

+7

其實這是所謂的名稱改變,變量不會變得真正私有。 http://docs.python.org/tutorial/classes.html#private-variables – jbochi 2010-01-14 13:12:44

+0

但是如果我不想讓我的客戶端使用某些方法?(即與客戶端無關的方法,如用於提供方法的方法向公衆提供服務但沒有用處) – appusajeev 2010-01-14 13:27:12

+0

然後,您正在尋找「非公開」成員,請參閱jbochi的答案。 – ezod 2010-01-14 13:41:39

31

其他答案提供了技術細節。我想強調Python與Python之間的哲學差異,如C++/Java(我認爲你基於你的問題熟悉)。

Python中的一般態度(和Per​​l就此而言)是屬性的'隱私'是編程器/解釋器對程序員的請求,而不是鐵絲網。這個想法總結在this mail,通常被稱爲「我們都同意成年人」,因爲它'假設'程序員有足夠的責任不去幹涉內部。領先的下劃線用作禮貌信息,表明屬性是內部的。

另一方面,如果你想要訪問一些應用程序的內部(一個值得注意的例子是像pydoc文檔生成器),你可以自由地這樣做。 Onus作爲程序員在你身上,知道你在做什麼,並且正確地做,而不是用語言來強迫你做事這是的方式。

+5

+1對於「我們都在這裏同意大人」:-) – jbochi 2010-01-14 14:01:21

+6

「而不是語言強迫你對事物的方式。」 縮進怎麼樣? :) – 2015-01-02 18:53:47

+0

@BorisMilner我認爲對此的迴應是:縮進使得代碼可讀並且有助於理解,所以它成爲一個好習慣。限制訪問成員不會有這樣的事情。如果有的話,它會進入一個相反的方向,因爲你必須說明哪些成員是私人的,哪些不是,增加視覺混亂。 – Zelphir 2017-05-29 12:28:14

5

Python中沒有任何其他訪問保護機制的private。在Python style guide中有一個約定用於向你的班級的用戶表明他們不應該訪問某個屬性。

  • _single_leading_underscore:弱的「內部使用」指標。例如。 from M import *不導入名稱以下劃線開頭的對象。

  • single_trailing_underscore_:按慣例使用以避免與Python關鍵字衝突,例如, Tkinter.Toplevel(master, class_='ClassName')

  • __double_leading_underscore __double_leading_underscore:當命名類屬性時,調用名稱修改(在類FooBar中,__boo變爲_FooBar__boo;參見下文)。

4

Python不直接支持隱私。程序員需要知道何時可以安全地從外部修改屬性,但無論如何用python,你可以實現像私人小竅門一樣的東西。 現在讓我們看看一個人可以將任何東西都隱藏起來。

 
class Person(object): 

    def __priva(self): 
     print "I am Private" 

    def publ(self): 
     print " I am public" 

    def callpriva(self): 
     self.__priva() 

現在,當我們將執行:

 
>>> p = Person() 
>>> p.publ() 
I am public 
>>> p.__priva() 
Traceback (most recent call last): 
    File "", line 1, in 
    p.__priva() 
AttributeError: 'Person' object has no attribute '__priva' 
​#Explanation : You can see here we are not able to fetch that private method directly. 
>>> p.callpriva() 
I am Private 
#​Explanation : Here we can access private method inside class​ 

那怎麼有人可以訪問變量?
你可以這樣做:

 
>>>p._Person__priva 
I am Private 

哇,居然Python是否得到任何變量開始雙下劃線的「翻譯」,加入一個下劃線和類名的開頭:

注意:如果你不想改變這個名稱,但你仍然想發送一個信號讓其他對象遠離,你可以使用一個帶有初始下劃線的初始下劃線名稱,不用導入的星號導入(從模塊導入* )
例如:

 
#test.py 
def hello(): 
    print "hello" 
def _hello(): 
    print "Hello private" 

#---------------------- 
 
#test2.py 
from test import * 
print hello() 
print _hello() 

輸出 - >

 
hello 
Traceback (most recent call last): 
    File "", line 1, in 
NameError: name '_hello' is not defined 

現在,如果我們將手動調用_hello。

 
#test2.py 
from test import _hello , hello 
print hello() 
print _hello() 

輸出 - >

 
hello 
hello private 

最後:Python中並沒有真正有一個等效加密支持,雖然單 和雙下劃線最初做在一定程度上給你的隱私

兩級
-2

如果你想使一個方法或數據成員在Python中是私有的,使用__setattr __

class Number: 
    def __init__(self,value): 
     self.my_private = value 

    def __setattr__(self, my_private, value): 
     # the default behavior 
     # self.__dict__[my_private] = value 
     raise Exception("can't access private member-my_private") 


def main(): 
    n = Number(2) 
    print(n.my_private) 

if __name__ == '__main__': 
    main() 
+0

爲什麼答案沒有用? 它將使「my_private」成員prive。 – liorb87 2015-12-02 17:41:50

+1

這沒有用,因爲它不起作用。這不僅不創建私人成員,它實際上不起作用。 Number(2)的構造函數不起作用,因爲即使Number自己的init函數也不能設置任何成員。 – 2016-07-21 22:18:12

1

這可能會實現:

import sys, functools 

def private(member): 
    @functools.wraps(member) 
    def wrapper(*function_args): 
     myself = member.__name__ 
     caller = sys._getframe(1).f_code.co_name 
     if (not caller in dir(function_args[0]) and not caller is myself): 
     raise Exception("%s called by %s is private"%(myself,caller)) 
     return member(*function_args) 
    return wrapper 

class test: 
    def public_method(self): 
     print('public method called') 

    @private 
    def private_method(self): 
     print('private method called') 

t = test() 
t.public_method() 
t.private_method() 
1

這是有點兒一個1-O-N-G的答案,但我認爲它會在這裏真正的問題的根源 - 可見範圍。當我闖入這個時候,就掛在那裏!

只需導入模塊不一定給它的所有類或方法的應用程序開發人員訪問;如果我實際上看不到模塊源代碼,我將如何知道可用的內容?有些人(或者某些人)不得不告訴我我能做些什麼,並解釋如何使用我允許使用的功能,否則整個事情對我來說都沒用。

基於基本類和經由進口模塊的方法的那些開發更高級別的抽象都帶有一個規範文檔 - 不是實際的源代碼。

模塊規範描述了客戶端開發人員可以看到的所有功能。在處理大型項目和軟件項目團隊時,模塊的實際執行應始終保持對使用它的人的隱藏 - 這是一個帶有與外界交互界面的黑盒子。對於OOD純粹主義者,我認爲技術術語是「脫鉤」和「一致性」。模塊用戶只需要知道接口方法而不用擔心執行的細節。

的模塊應該NEVER沒有首先改變其基本規範文件,這可能需要在之前改變代碼一些組織審查/批准改變。作爲業餘愛好程序員(現在退役),我開始了一個新的模塊,其中spec doc實際上是作爲模塊頂部的一個巨型註釋塊寫出來的,這將是用戶在spec庫中實際看到的部分。既然它只是我,我還沒有建立一個圖書館,但它很容易做到。

然後,我通過寫各種類和方法,但沒有功能性機構開始編碼 - 只是空的打印語句,如「打印()」 - 就足以允許模塊沒有語法錯誤編譯。當這一步完成時,我編譯完成的空模塊 - 這是我的規範。如果我在一個項目團隊工作,我會提出這個規範/接口來評論&評論,然後進行充實身體。

我充實每次打開一個方法之一的機構和相應的編譯,確保語法錯誤是在即時立即修復。這也是開始在底部編寫一個臨時「主要」執行部分以便在編寫代碼時測試每種方法的好時機。編碼/測試完成後,所有測試代碼都會被註釋掉,直到您需要更新時才需要更新。

在現實世界的開發團隊,規範的註釋塊也將出現在文檔控件庫,但這是另一個故事。重點是:作爲模塊客戶端,您只能看到這個規範而不是源代碼。 PS:早在時間開始之前,我曾在國防航空航天界工作,我們做了一些非常酷的東西,但是像專有算法和敏感系統控制邏輯這樣的東西在超級安全的軟件庫中被嚴格拱起並加密。我們可以訪問模塊/包接口,但不能訪問黑盒實現主體。有一個文檔管理工具可以處理所有系統級設計,軟件規格,源代碼和測試記錄 - 它們全部同步在一起。政府對軟件質量保證標準有嚴格要求。任何人都記得一種叫做「Ada」的語言?這是我多大了!