2014-10-06 65 views
5

這是怎麼回事?從客觀和功能角度來看?如何在Python中進行封裝?

import sys 

class EncapsulationClass(object): 

    def __init__(self): 
    self.privates = ["__dict__", "privates", "protected", "a"] 
    self.protected = ["b"] 

    print self.privates 

    self.a = 1 
    self.b = 2 
    self.c = 3 
    pass 

    def __getattribute__(self, name): 
    if sys._getframe(1).f_code.co_argcount == 0: 
     if name in self.privates: 
     raise Exception("Access to private attribute \"%s\" is not allowed" % name) 
     else: 
     return object.__getattribute__(self, name) 
    else: 
     return object.__getattribute__(self, name) 

    def __setattr__(self, name, value): 
    if sys._getframe(1).f_code.co_argcount == 0: 
     if name in self.privates: 
     raise Exception("Setting private attribute \"%s\" is not allowed" % name) 
     elif name in self.protected: 
     raise Exception("Setting protected attribute \"%s\" is not allowed" % name) 
     else: 
     return object.__setattr__(self, name, value) 
    else: 
     return object.__setattr__(self, name, value) 


example = EncapsulationClass() 

example.a = 10 # Exception: Setting private attribute "a" is not allowed 
example.b = 10 # Exception: Setting protected attribute "b" is not allowed 
example.c = 10 # example.c == 10 

example.__dict__["privates"] # Exception: Setting protected attribute "b" is not allowed 

這樣做會有什麼問題?

有什麼更好的方法來實現Python中的封裝?

+3

...你是什麼意思?你認爲什麼是錯的?它運行嗎? – jonrsharpe 2014-10-06 12:53:34

+1

可能在[codereview](http://codereview.stackexchange.com/)中提出 – 2014-10-06 12:56:28

+0

它似乎工作正常,是的,但我經常看到有人說「python沒有封裝」,所以推測它不能「不要這樣簡單。 – will 2014-10-06 12:57:39

回答

31

Python已封裝 - 您正在使用它在您的班級。

它沒有的是訪問控制,如私人和受保護的屬性。然而,在Python,有一個屬性命名慣例由前綴與一個或兩個下劃線屬性表示私有屬性,例如:

self._a 
self.__a 

以單下劃線表示一類的一個屬性,應考慮用戶私人的類,不應該直接訪問。

雙下劃線表示相同,但​​是,Python會在某種程度上破壞屬性名稱以試圖隱藏它。

class C(object): 
    def __init__(self): 
     self.a = 123 # OK to access directly 
     self._a = 123 # should be considered private 
     self.__a = 123 # considered private, name mangled 

>>> c = C() 
>>> c.a 
123 
>>> c._a 
123 
>>> c.__a 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'C' object has no attribute '__a' 
>>> c._C__a 
123 

您可以在最後一個例子,這個名字改爲從__a_C__a看到,儘管它仍然是班級爲self.__a中訪問。

+1

我知道所有這一切,但這與我所談論的並不完全相同,似乎有兩種封裝的定義。其中之一就是將幾段數據打包成一個類,另一個是實際隱藏數據/使其無法訪問。 '__a'的東西,我很好,但這不是我所追求的 - 我更感興趣的是模仿在其他語言中看到的'private','protected'等變量修飾符。 – will 2014-10-06 13:12:25

+0

我對整個'__a'變量的理解只不過是讓人們使用你的代碼知道他們不是你打算在模塊外部使用的變量 - 而且這樣的人不會依賴它們,因爲他們隨時都有可能改變。 – will 2014-10-06 13:13:31

1

那麼,Python沒有封裝作爲一種「哲學」決定,就像我們用鴨子打字很多一樣。就我個人而言,我沒有看到在Python代碼中使用私有或受保護參數的要點。

代碼的說起來,這似乎很好地工作具有以下getter和setter方法:

def set_a(self, v): 
    self.a = v 

def get_a(self): 
    return self.a 

,如果你做如下修改__的getAttribute __(自我,名)的最後一行:

return object.__getattribute__(self, name) 

但是,您可以作爲mhawke提到使用某種可變保護,如果你以__爲前綴的私有變量概念。另外,Daniel的評論指出了你的列表參數的限制。您可以通過在私人列表中添加「私人」和「受保護」來保留受保護的「獲取/設置」行爲。