使用字符串调用Python实例的私有属性

问题描述:

对于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

双下划线调用蟒蛇name-mangling

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

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

一般来说,python这样做的原因是允许程序员避免与可能想要定义具有相同名称的方法(但不覆盖基类中的方法)的子类冲突。所以,那就是当你应该使用双下划线前缀属性。如果你没有这种情况,那么你最好使用单下划线(它更习惯)。

带有双下划线(例如__foo)的属性为mangled,以使其更难访问它们。规则如下:

Since there is a valid use-case for class-private members (namely to avoid name *es 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