2016-07-28 74 views
1

對於Python中的OOP(以及一般的Python),我有些不熟悉,當我嘗試從一個實例中訪問實例私有屬性時遇到了問題的方法,並使用字符串作爲屬性名稱。使用字符串調用Python實例的私有屬性

這裏的目標是,當調用對象getDetails()方法時,基本上會有一個將顯示的屬性列表(在鍵值格式中)。只要列表中的所有屬性都不是對象中的私有屬性,它就可以正常工作。如果所有的屬性都是而不是私有,那麼它似乎工作正常。

在下面的示例中,您可以看到我有3個屬性foo,_bar__baz。在TheClass.getDetails()方法,如果__baz行註釋掉,它工作完全正常:

class TheClass(object): 
    def __init__(self): 
     self.foo = 'One..' 
     self._bar = 'Two..' 
     self.__baz = 'Three..' 

    def getDetails(self): 
     display = [ 
      'foo' 
      ,'_bar' 
      #,'__baz' 
     ] 

     print "DebugInfo:" 
     for key in display: 
      print '{0:<15}: {1:<20}'.format(key, self.__dict__[ key ] or 'N/A') 

TheClass().getDetails() 

""" Output: 
DebugInfo: 
foo   : One.. 
_bar   : Two.. 
""" 

然而,當我取消對display陣列中的__baz項,我得到拋出的異常:

DebugInfo: 
foo   : One.. 
_bar   : Two.. 
Traceback (most recent call last): 
    File "getattr.py", line 18, in <module> 
    TheClass().getDetails() 
    File "getattr.py", line 16, in getDetails 
    print '{0:<15}: {1:<20}'.format(key, self.__dict__[ key ] or 'N/A') 
KeyError: '__baz' 

我試圖改變屬性的引用方式,用getattr(self, key)替換self.__dict__[ key ],但這只是導致了相同的錯誤:

DebugInfo: 
foo   : One.. 
_bar   : Two.. 
Traceback (most recent call last): 
    File "getattr.py", line 18, in <module> 
    TheClass().getDetails() 
    File "getattr.py", line 16, in getDetails 
    print '{0:<15}: {1:<20}'.format(key, getattr(self, key) or 'N/A') 
AttributeError: 'TheClass' object has no attribute '__baz' 

如果我只是硬編碼性能,那麼顯然這將正常工作:

class TheClass(object): 
    def __init__(self): 
     self.foo = 'One..' 
     self._bar = 'Two..' 
     self.__baz = 'Three..' 

    def getDetails(self): 
     print "DebugInfo:" 
     print '{0:<15}: {1:<20}'.format('foo', self.foo or 'N/A') 
     print '{0:<15}: {1:<20}'.format('_bar', self._bar or 'N/A') 
     print '{0:<15}: {1:<20}'.format('__baz', self.__baz or 'N/A') 

TheClass().getDetails() 

""" Output: 
DebugInfo: 
foo   : One.. 
_bar   : Two.. 
__baz   : Three.. 
""" 

但我需要這是更有活力的一點。那麼是否有人知道如何才能使這個工作?

謝謝!

P.S.我使用Python的2.7.11

回答

1

雙下劃線調用蟒蛇name-mangling

>>> class Foo(object): 
... def __init__(self): 
...  self.__private = 1 
... 
>>> f = Foo() 
>>> vars(f) 
{'_Foo__private': 1} 

你可以看到,它改變__property_<classname>__property

一般來說,python這樣做的原因是允許程序員避免與可能想要定義具有相同名稱的方法(但不覆蓋基類中的方法)的子類衝突。所以,那就是當你應該使用雙下劃線前綴屬性。如果你沒有這種情況,那麼你最好使用單下劃線(它更習慣)。

2

帶有雙下劃線(例如__foo)的屬性爲mangled,以使其更難訪問它們。規則如下:

Since there is a valid use-case for class-private members (namely to avoid name clashes of names with names defined by subclasses), there is limited support for such a mechanism, called name mangling. Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.

因此,在查找表中,你需要去尋找,而不是僅僅__baz符號_TheClass__baz