__name
names are class private; such names are prefixed, at compile time, with another underscore and the class name. The purpose is to protect the names from accidental clashes with names used in subclasses. These names are not meant to be private to outside callers.
Quoting the Reserved classes of identifiers section:
__*
Class-private names. Names in this category, when used within the context of a class definition, are re-written to use a mangled form to help avoid name clashes between “private” attributes of base and derived classes.
and the Identifiers (Names) section:
Private name mangling: When an identifier that textually occurs in a class definition begins with two or more underscore characters and does not end in two or more underscores, it is considered a private name of that class. Private names are transformed to a longer form before code is generated for them. The transformation inserts the class name, with leading underscores removed and a single underscore inserted, in front of the name. For example, the identifier __spam
occurring in a class named Ham
will be transformed to _Ham__spam
. This transformation is independent of the syntactical context in which the identifier is used.
What happens in your case is that exec()
postpones compilation, effectively compiling that call in isolation. The class context is gone, so no mangling takes place.
As such, you need to apply the automatic prefixing manually:
exec('self.a = self._A__funct()')
If you are using Python 3, you could use the __class__
closure normally available for the super()
function to access the class name the current method is defined for:
exec('self.a = self._{0.__name__}__funct()'.format(__class__))
Now, unless you actually plan for your class to be widely subclassed in third-party code that should not have to worry about accidentally clashing with internal implementation details, you should not be using double-underscore names at all. Stick with single-underscore names instead.