A. Luo A. Luo - 1 month ago 14
Python Question

Python setattr() not assigning value to class member

I'm trying to set up a simple test example of setattr() in Python, but it fails to assign new value to the member. I've tried assigning with setattr(self, "bar", 1) too. Can someone explain what is happening under the hood. I'm new to python, so please forgive my elementary question.


Python 2.7.12 (default, Jun 29 2016, 14:05:02)
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.


class Foo(object):
__bar = 0
def modify_bar(self):
print(self.__bar)
setattr(self, "__bar", 1)
print(self.__bar)


>>> foo = Foo()

>>> foo.modify_bar()

0

0

Answer

A leading double underscore invokes python name-mangling.

So:

class Foo(object):
    __bar = 0  # actually `_Foo__bar`
    def modify_bar(self):
        print(self.__bar)  # actually self._Foo__bar
        setattr(self, "__bar", 1)
        print(self.__bar)  # actually self._Foo__bar

Name mangling only applies to identifiers, not strings, which is why the __bar in the setattr function call is unaffected.

class Foo(object):
    _bar = 0
    def modify_bar(self):
        print(self._bar)
        setattr(self, "_bar", 1)
        print(self._bar)

should work as expected.

Leading double underscores are generally not used very frequently in most python code (because their use is typically discouraged). There are a few valid use-cases (mainly to avoid name clashes when subclassing), but those are rare enough that name mangling is generally avoided in the wild.