Search code examples
pythonscopeprivate

Truly Private Variables in Python 3


So I know the way to make a variable "private" in python like this:

class Foo:
    def __init__(self):
        self.__private = 'bar'

This "works" and doesn't, as shown below:

foo = Foo()
'__private' in vars(foo) #False
'_Foo__private' in vars(foo) #True

Now, I understand this is the way to make private variables in python and I like this way. It allows you to mangle names so that no subclasses accidentally override this (because it begins with the class's name), and that nobody will accidentally use it. It also gives you the power to change the private variables if you know what you are doing. Also, it is the best way to do it, because truly private variables are impossible.

Or so I thought.

Recently, I was reading PEP 8 and I saw this line:

We don't use the term "private" here, since no attribute is really private in Python (without a generally unnecessary amount of work).

This quote is found in the Designing for Inheritance section of PEP 8.

Note the phrase "without a generally unnecessary amount of work". I am now sure that there must be a way to get truly private variables in python. How would I do that?

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).

Also, the __dict__ attribute is annoying when trying to do this because it holds references to all instance variables.

I also thought of metaclasses, but those seem to have the same problems as __getattribute__.

Thoughts?


Note: I understand that any way to make truly private variables in python should never be done in productive code. I just want to know how it could be done.


Solution

  • 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.