2

To what extent can a class "protect" one of it's attributes from outside access?

For example, a class with a conventional _secret attribute, the original value is easily accessed:

class Paranoid(object):
    def __init__(self):
        self._secret = 0

    def set(self, val):
        self._secret = val * 10

    def get(self):
        return self._secret / 10

p = Paranoid()
p.set(123)
print p.get() # 123
print p._secret # 1230, should be inaccessible

How can access to _secret be made more difficult?

There's no practical application to this, I'm just curious if there's novel ways to make it more difficult to access (within the context of Python - so ignoring the fact you could, say, attach a debugger to the Python process and inspect the memory)

dbr
  • 165,801
  • 69
  • 278
  • 343
  • I'm sure this is a duplicate, I recall seeing a question which had a bunch of answers with interesting attempts at protecting the attribute.. but my searches found nothing – dbr May 08 '12 at 16:08
  • https://plus.google.com/114760865724135687241/posts/HAqFzi3fnux – bossylobster May 08 '12 at 16:09
  • 4
    [We're all consenting adults here](http://stackoverflow.com/questions/70528/why-are-pythons-private-methods-not-actually-private). – Óscar López May 08 '12 at 16:13
  • @ÓscarLópez Indeed, but there's nothing wrong with consenting adults playing hide-and-seek :P – dbr May 09 '12 at 05:46

2 Answers2

6

You're probably looking for getters and setters. A slightly less complecated approach is to use __secret, which will invoke name mangling to turn it into _Paranoid__secret.

But yes, I should note that the python community doesn't really value privacy the way some languages do. Or as the saying goes we're all consenting adults here.

Shep
  • 7,990
  • 8
  • 49
  • 71
  • 1
    It is the same as the OP example, since you can easily modify the `_Paranoid__secret` variable. He wants the means to duplicate the `private` access restriction available on other languages, enforced by the compiler or by other means. – vz0 May 08 '12 at 16:27
  • yeah, this isn't really the correct answer. Objects call their attributes through the same interface the user does, which makes true privacy impossible as far as I know. You could overload `__setattr__` and `__getattribute__` to make calls to the superclass for public attributes (and deny for private), but the user can do that with the private attribute too. – Shep May 09 '12 at 03:42
4
>>> def Paranoid():
...     _secret_dict = {'_secret': 0}
...     class ParanoidClass(object):
...             def set(self, val):
...                     _secret_dict['_secret'] = val * 10
...             def get(self):
...                     return _secret_dict['_secret'] / 10
...     return ParanoidClass()
... 
>>> p = Paranoid()
>>> p.set(123)
>>> p.get()
123

This reminds me of a Steve Yegge blog post.

vz0
  • 32,345
  • 7
  • 44
  • 77
  • Doesn't make writing the class members easily for any public interface, but effective. +1 for the blog post. :D – Casey Kuball May 08 '12 at 16:26
  • 1
    does not work: `>>> p.get.im_func.func_closure[0].cell_contents {'_secret': 1230}` – ch3ka May 08 '12 at 16:26
  • Wow, I didn't realize closures would work for methods defined in a class defined in a function! You could make your "secret" variable an `object()` so you could store attributes on it; that's probably cleaner. Still, this isn't truly private, just a bit hidden: `print p.get.func_closure[0].cell_contents` – kindall May 08 '12 at 16:29
  • @vz0 actually, I disagree. It is just different syntax. so why not stick with the clean old `_secret`? – ch3ka May 08 '12 at 16:31
  • 1
    @ch3ka Of course I agree that in the real world, using the plain old `this._secret` variable is the best. This is just a funny intellectual exercise. – vz0 May 08 '12 at 16:34