2017-01-13 8 views
1

Я знаю, что большинство из вас остается за этим exec не следует использовать, но у меня есть некоторые проблемы.«exec» не работает с приватным методом Python

Вот минимальный пример, который работает:

class A: 
    def __init__(self): 
     exec('self.a = self.funct()') 
    def funct(self): 
     return 1 
    def ret(self): 
     return self.a 
> obj = A() 
> obj.ret() 
1 

Но, когда я делаю:

class A: 
    def __init__(self): 
     exec('self.a = self.__funct()') 
    def __funct(self): 
     return 1 
    def ret(self): 
     return self.a 
> obj = A() 
AttributeError: 'A' has no attribute '__funct' 

Кто-нибудь знает, почему это различие?

+1

Обратите внимание, что имена '__' - ** class ** private. Это не то же самое, что и модели конфиденциальности на других языках. –

ответ

3

__name фамилии класс частный; такие имена имеют префикс во время компиляции с другим символом подчеркивания и именем класса. Цель состоит в том, чтобы защитить имена от случайных столкновений с именами, используемыми в подклассах. Этими именами являются , а не, предназначенные для частных лиц.

Цитируя Reserved classes of identifiers section:

__*
имена классов-частного. Имена этой категории, используемые в контексте определения класса, переписываются для использования искаженной формы, чтобы избежать столкновений имен между «частными» атрибутами базового и производного классов.

и Identifiers (Names) section:

Личное имя коверкая: Когда идентификатор, который текстуально происходит в определении класса начинается с двух или более символов подчеркивания и не заканчивается в двух или более символов подчеркивания, его считается частным именем этого класса. Частные имена преобразуются в более длинную форму до того, как для них генерируется код. Преобразование вставляет имя класса, с удалением ведущих подчеркиваний и добавлением одного подчеркивания перед именем. Например, идентификатор __spam, происходящий в классе с именем Ham, будет преобразован в _Ham__spam. Это преобразование не зависит от синтаксического контекста, в котором используется идентификатор.

Что происходит в вашем случае является то, что exec() откладывает компиляцию, эффективно компиляции этот вызов в изоляции. Контекст класса ушел, так что никаких изменений не происходит.

Таким образом, вы должны применить автоматическую предваряя вручную:

exec('self.a = self._A__funct()') 

Если вы используете Python 3, вы можете использовать __class__ закрытия normally available for the super() function доступ к имени класса в настоящее время метод определяется для:

exec('self.a = self._{0.__name__}__funct()'.format(__class__)) 

Теперь, если вы фактически не планируете, чтобы ваш класс был широко подклассифицирован в стороннем коде, который не должен беспокоиться о случайном столкновении с внутренними деталями реализации, вы не должны использовать double-u nderscore имена вообще. Придерживайтесь имен с одним подчеркиванием.

0

Индивидуальные методы Python «замаскированы» под другим идентификатором, отличным от указанного в коде, вы можете получить к ним доступ как _classname__privateAttribute.

проводки это конкретно:

class A: 
    def __init__(self): 
     exec('self.a = self._A__funct()') 
    def __funct(self): 
     print("Hello") 
    def ret(self): 
     return self.a 

obj = A() 

Я положил ответ печати там, чтобы обнаружить, если он работал, и это сделали!