views:

63

answers:

2

The following code:

class MyClass():
    def test(self):
        self.__x = 0

    def __setattr__(self, name, value):
        print name

    def __getattr__(self, name):
        print name
        raise AttributeError(name)

x = MyClass()
x.test()
x.__y

Outputs:

_MyClass__x
__y
Traceback (most recent call last):
...
AttributeError: __y

The documentation is utterly unhelpful stating the "name" is the "name of the attribute", yet for some reason it's different depending on whether you are setting it or getting it.

What I want to know is:

  • Am I doing something fundamentally wrong here?
  • How do I get x in the first case instead of _MyClass__x?
+4  A: 

The double underscore invokes name mangling. If you don't need name mangling, don't use double undescore

http://stackoverflow.com/questions/1301346/the-meaning-of-a-single-and-a-double-underscore-before-an-object-name-in-python

From the Python docs

9.6. Private Variables

“Private” instance variables that cannot be accessed except from inside an object, don’t exist in Python. However, there is a convention that is followed by most Python code: a name prefixed with an underscore (e.g. _spam) should be treated as a non-public part of the API (whether it is a function, a method or a data member). It should be considered an implementation detail and subject to change without notice.

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.

Note that the mangling rules are designed mostly to avoid accidents; it still is possible to access or modify a variable that is considered private. This can even be useful in special circumstances, such as in the debugger.

Notice that code passed to exec, eval() or execfile() does not consider the classname of the invoking class to be the current class; this is similar to the effect of the global statement, the effect of which is likewise restricted to code that is byte-compiled together. The same restriction applies to getattr(), setattr() and delattr(), as well as when referencing __dict__ directly.

gnibbler
Oops, I missed the underscores from the `__y`. I've corrected it now. There's still an asymmetry, but I think you've hit on the core problem.
Draemon
A: 

I'm not sure exactly why this occurs, but if you use _x rather than __x it works as you would expect.

ar
it's called name mangling: http://docs.python.org/tutorial/classes.html#private-variables
SilentGhost
Indeed. What's interesting is that `__x__` doesn't get name mangled.
ar
@ar, `__x__` has another special meaning
gnibbler