When trying to access __variables from a class, the parser assumes the 2 underscores are private relative to the current class. Notice how an unrelated function gets a "private" variable.
Is this a bug?
>>> def f(): pass ...>>> class A: ... def g(self): ... f.__x = 1 ... def h(): ... pass ... h.__y = 2 ... return h ...>>> z = A().g()>>> dir(z) ['_A__y', '__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__get_ _', '__getattribute__', '__hash__', '__init__', '__module__', '__name__', '__new __', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'func_ closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']>>> dir(f) ['_A__x', '__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__get_ _', '__getattribute__', '__hash__', '__init__', '__module__', '__name__', '__new __', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'func_ closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']
Tested on python 2.5 and 3.2
-
Working as expected. Granted, what you're doing with them is unusual, but those attributes belong to the class, wherever they happen to be.kelm– kelm2011年08月06日 13:30:30 +00:00Commented Aug 6, 2011 at 13:30
2 Answers 2
This is a well documented behavior.
This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.
3 Comments
__? I would say that it is a mistake to assign a value to f.__x outside of a class definition. A single underscore is sufficient to mark a variable as "private"; the purpose of name mangling is not really privacy but collision avoidance in the context of class inheritance.Here’s a way to declare private variables: overload the __setattr__ (and other many methods about attributes) method, in the method, you can check current executing method is in the own class. If it is true, let it pass. Otherwise, you can raise an exception, or you can use your own customize error handle logic. (Tips: use inspect.stack function)