Private members in Python
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.
So, for example,
class Test:
def __private_symbol(self):
pass
def normal_symbol(self):
pass
print dir(Test)
will output:
['_Test__private_symbol',
'__doc__',
'__module__',
'normal_symbol']
__private_symbol
should be considered a private method, but it would still be accessible through _Test__private_symbol
.
Does Python have “private” variables in classes?
It's cultural. In Python, you don't write to other classes' instance or class variables. In Java, nothing prevents you from doing the same if you really want to - after all, you can always edit the source of the class itself to achieve the same effect. Python drops that pretence of security and encourages programmers to be responsible. In practice, this works very nicely.
If you want to emulate private variables for some reason, you can always use the __
prefix from PEP 8. Python mangles the names of variables like __foo
so that they're not easily visible to code outside the namespace that contains them (although you can get around it if you're determined enough, just like you can get around Java's protections if you work at it).
By the same convention, the _
prefix means _variable
should be used internally in the class (or module) only, even if you're not technically prevented from accessing it from somewhere else. You don't play around with another class's variables that look like __foo
or _bar
.
Truly Private Variables in Python 3
I have tried overriding getattribute, but the problem is that there is no way to tell if the call is coming from inside the class or not (that I am aware of).
You can use the inspect
module to find the name and module of the calling function, which you could compare against a whitelist.
But inspect
also has getattr_static
, which can bypass any __getattribute__
.
Nothing is truly private in Python. There are ways to make access difficult, but there are always ways around those ways.
The only solution then, is outside of the current Python interpreter. You could use a foreign function interface to some other more secure language or a remote procedure call (e.g. xmlrpc) to the same or to another Python interpreter running in a subprocess, or even one running as a different user with different permissions. The private variable and all the functions allowed to access it will live outside the current interpreter. Then there's no way to inspect it.
This type of privilege separation is even one of the stated use cases for the Pyro RPC library.
Declaring private variable in Python
In short: there is no way to have a truly "private" class member in Python. The runtime simply doesn't support memory protection in the way, ex, Java does.
The double underscore prefix mangles the name so it includes the name of the class it's used in (ex, __total
would become _Balance__total
), but this is primarily used to allow subclasses to define names which appear the same, but reference different fields.
The standard convention in Python is to use a single underscore prefix — _total
— for class members which should be treated as be "private" or "protected", then trust that the other developers will be adults and respect that (of course, this isn't always a safe assumption…)
It is very rare to see modern Python code use double-underscore attributes.
How Do I Make Private Variables Inaccessable in Python?
What you are trying to do is not possible in Python.
“Private” instance variables that cannot be accessed except from inside an object don’t exist in Python.
https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
public or private attribute in Python ? What is the best way?
Typically, Python code strives to adhere to the Uniform Access Principle. Specifically, the accepted approach is:
- Expose your instance variables directly, allowing, for instance,
foo.x = 0
, notfoo.set_x(0)
- If you need to wrap the accesses inside methods, for whatever reason, use
@property
, which preserves the access semantics. That is,foo.x = 0
now invokesfoo.set_x(0)
.
The main advantage to this approach is that the caller gets to do this:
foo.x += 1
even though the code might really be doing:
foo.set_x(foo.get_x() + 1)
The first statement is infinitely more readable. Yet, with properties, you can add (at the beginning, or later on) the access control you get with the second approach.
Note, too, that instance variables starting with a single underscore are conventionally private. That is, the underscore signals to other developers that you consider the value to be private, and they shouldn't mess with it directly; however, nothing in the language prevents them from messing with it directly.
If you use a double leading underscore (e.g., __x
), Python does a little obfuscation of the name. The variable is still accessible from outside the class, via its obfuscated name, however. It's not truly private. It's just kind of ... more opaque. And there are valid arguments against using the double underscore; for one thing, it can make debugging more difficult.
Why are Python's 'private' methods not actually private?
The name scrambling is used to ensure that subclasses don't accidentally override the private methods and attributes of their superclasses. It's not designed to prevent deliberate access from outside.
For example:
>>> class Foo(object):
... def __init__(self):
... self.__baz = 42
... def foo(self):
... print self.__baz
...
>>> class Bar(Foo):
... def __init__(self):
... super(Bar, self).__init__()
... self.__baz = 21
... def bar(self):
... print self.__baz
...
>>> x = Bar()
>>> x.foo()
42
>>> x.bar()
21
>>> print x.__dict__
{'_Bar__baz': 21, '_Foo__baz': 42}
Of course, it breaks down if two different classes have the same name.
Does python support private variables?
There is a lot of literature on this topic, but in short:
Python is different to programming languages that have actually "private" attributes in that no attribute can be truly inaccessible by other functions. Yes, we can simulate the behaviour of languages like Java using property
, as you've shown, but that is kind of fudging "true" private attributes. What property
actually is is a higher-order function (well, technically, it's a decorator), so when you call c.x
, although it acts as a property, you're really referring to a function that controls whether you can use the getters and setters defined in it.
But just because c.x
doesn't allow direct read access, doesn't mean that you can't call print c._x
(as @avigil pointed out). So c._x
isn't really private - it's just as easily accessible as any other attribute belonging to the C
class. The fact that its name starts with an underscore is just a convention - a signal to fellow programmers: "Please don't handle this variable directly, and use the getters/setters instead" (if available).
Access private variables in injected method - python
The name mangling of "private" members is strictly done within class definitions. To achieve the desired purpose, which is to have self.__hidden
translated to self._Simulation_hidden
you need simply define it within an appropriately named class.
For example:
def make_mocked_method():
class Simulation:
# this is your code, but now its inside a class stanza so '__' will be mangled
def mocked_method(self):
print(type(self))
print(self.__dict__)
print(self.__hidden)
return Simulation.mocked_method
Now mocked_method
will access the desired attribute correctly:
simulation.mocked_update = MethodType(make_mocked_method(), simulation)
simulation.someloop()
gives:
<class '__main__.Simulation'>
{'finished': False, 'mocked_update': <bound method make_mocked_method.<locals>.Simulation.mocked_method of <__main__.Simulation object at 0x101c00a58>>, '_Simulation__hidden': -10}
-10
Extension
This relies on us hard coding the name of the class we're adding the method to (Simulation
). To avoid that we can instead use an exec
:
def make_mocked_method(cls):
txt = """class {}:
def mocked_method(self):
print(type(self))
print(self.__dict__)
print(self.__hidden)
""".format(cls.__name__)
ns = {}
exec(txt, ns)
return ns[cls.__name__].mocked_method
Unfortunately here the function we wish to add must be defined as text, it can't be some already defined arbitrary function object. (That might possibly be solved by using inspect
to find its source and then recompiling that source within a class stanza using exec
(and judicious choice of globals
).
Defining private module functions in python
In Python, "privacy" depends on "consenting adults'" levels of agreement - you can't force it (any more than you can in real life;-). A single leading underscore means you're not supposed to access it "from the outside" -- two leading underscores (w/o trailing underscores) carry the message even more forcefully... but, in the end, it still depends on social convention and consensus: Python's introspection is forceful enough that you can't handcuff every other programmer in the world to respect your wishes.
((Btw, though it's a closely held secret, much the same holds for C++: with most compilers, a simple #define private public
line before #include
ing your .h
file is all it takes for wily coders to make hash of your "privacy"...!-))
Related Topics
Sqlalchemy Orm Conversion to Pandas Dataframe
Convert List to Tuple in Python
Why Aren't Superclass _Init_ Methods Automatically Invoked
N-Grams in Python, Four, Five, Six Grams
Login Credentials Not Working with Gmail Smtp
Best Way to Check Function Arguments
How to Equalize the Scales of X-Axis and Y-Axis in Matplotlib
Python: Find_Element_By_Css_Selector
What's the Best Way to Generate a Uml Diagram from Python Source Code
Flask at First Run: Do Not Use the Development Server in a Production Environment
Differencebetween Encode/Decode
Gradient Descent Using Python and Numpy
How to Uninstall a Package Installed with Pip Install --User
How to Get Item's Position in a List
How to Check Blas/Lapack Linkage in Numpy and Scipy
How to Install Python 3.X and 2.X on the Same Windows Computer
Strange Behavior of Lists in Python
How to Get Around Declaring an Unused Variable in a for Loop