2016-07-28 3 views
1

Я немного новичок в OOP в Python (и вообще 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.. 
""" 

Однако, когда я раскомментировать __baz записи в display массиве, я получаю исключение брошенное:

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' 

Я попытался изменить способ ссылки на объект, отключив self.__dict__[ key ] с getattr(self, key), но это привело к той же ошибке:

Если я просто жёстко свойства, то, очевидно, что будет работать нормально:

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.

Таким образом, в таблице поиска, вам нужно искать символ _TheClass__baz вместо просто __baz.

Смежные вопросы