QxQ
QxQ

Reputation: 675

is this code truly private? (python)

I am trying to make python allow private variable, so I made this decorator that you put at the begging of a class so that every function will get an additional private parameter that they can modify to be what they want. as far as I can tell, it is impossible to get the variables from outside the class, but I'm not a pro.

can anyone find a way to hack into the private object and get the values from it? is there a better way to do it than this?

python 2.7

#this is a decorator that decorates another decorator. it makes the decorator
#not loose things like names and documentation when it creates a new function
def niceDecorator(decorator):
    def new_decorator(f):
        g = decorator(f)
        g.__name__ = f.__name__
        g.__doc__ = f.__doc__
        g.__dict__.update(f.__dict__)
        return g
    new_decorator.__name__ = decorator.__name__
    new_decorator.__doc__ = decorator.__doc__
    new_decorator.__dict__.update(decorator.__dict__)
    return new_decorator

@niceDecorator
#this is my private decorator
def usePrivate(cls):

    prv=type('blank', (object,), {})
    #creates a blank object in the local scope
    #this object will be passed into every function in
    #the class along with self which has been renamed
    #as pbl (public).

    @niceDecorator
    #this is the decorator that gets applied to every function
    #in the class. in makes it also accept the private argument
    def decorate(func):
        def run(pub, *args, **kwargs):
            return func(pub,prv, *args, **kwargs)
        return run

    #this loops through every function in the class and applies the decorator
    for func in cls.__dict__.values():
        if callable(func):
            setattr(cls, func.__name__, decorate(getattr(cls, func.__name__)))

    return cls

#this is the class we are testing the private decorator with.
#this is what the user would program
@usePrivate
class test():

    #sets the value of the private variable
    def setValue(pbl,prv,arg):
        #pbl (public) is another name for self
        #prv (private) acts just like self except its private
        prv.test=arg

    #gets the value of the private variable
    def getValue(pbl,prv):
        return prv.test
a=test()
a.setValue(3)
print a.getValue()

Upvotes: 2

Views: 1482

Answers (4)

Tolli
Tolli

Reputation: 362

As others have said, there is still a way to get to the private variables. However, you can still get to private variables in c++. Consider this C++ example:

class PrivateEye
{
    private:
    int a;
    double b;
    char c;

    public:
    // ... public functions ...
};

PrivateEye detective;

double privateB = *((double *) ((void *) &detective + sizeof(detective.a)));

As you can see, it takes alot of work to get access to the private varible, so the person doing it needs to know enough to know the risks. So, if you have programmers using your _attribute private attribute, the solution you posted will be effective in making them think about it before messing with the private attributes. Using __attribute (double-underscore) will cause some name mangling, which also has the same effect of cause people to do a little more thinking before deciding to access the "private" attributes.

Edit: According to the second answer in Accessing private members , the C++ standard doesn't guarantee the order of member variables in a class, so you might have to experiment a little bit to get access to the private variable you want in the C++ example above.

Upvotes: 1

Ned Batchelder
Ned Batchelder

Reputation: 375912

There's always a way to get at things in Python, especially if you have the original source to read. Using kindall's example, add these lines to the end of your file:

print a.getValue.im_func.func_closure[0].cell_contents.test
a.getValue.im_func.func_closure[0].cell_contents.test = 17
print a.getValue()

Really, don't do this. There's a reason Python people say, "don't bother with private variables."

Upvotes: 4

kindall
kindall

Reputation: 184345

That's an interesting idea, but the wrapper functions you're using for the decorator will have a reference to the "private" object in their func_closure attribute. So your "private" variable is accessible as a.getValue.func_closure[0].cell_contents.test. (You can use any wrapped function to get to your "private" object, not just getValue.)

Generally this sort of technique will only serve to annoy other programmers who are using your code.

Upvotes: 9

Gareth Latty
Gareth Latty

Reputation: 89087

In short: Don't do this.

There is no need to make things truly private in Python. The people using your software can see if something is marked as private (variable name begins with _), so they know. If they still want to access it, why stop them?

I'm sure there is also a way around your code - Python has incredible amounts of introspective code, and modifying classes is easy to do. It's virtually impossible to lock anything down if someone really wants to get to it.

It's also worth noting that in Python, setters/getters are pointless. The aim is to allow you to add in code on setting/getting an attribute, which python allows you to do using the property() builtin.

Upvotes: 10

Related Questions