Private variables

Rasjid Wilcox rasjidw at gmail.com
Wed Sep 1 23:59:44 EDT 2010


On 2 September 2010 12:22, Ryan Kelly <ryan at rfk.id.au> wrote:
> On Thu, 2010-09-02 at 12:06 +1000, Ryan Kelly wrote:
>> On Thu, 2010-09-02 at 11:10 +1000, Rasjid Wilcox wrote:
>> > Hi all,
>> >
>> > I am aware the private variables are generally done via convention
>> > (leading underscore), but I came across a technique in Douglas
>> > Crockford's book "Javascript: The Good Parts" for creating private
>> > variables in Javascript, and I'd thought I'd see how it translated to
>> > Python. Here is my attempt.
>> >
>> > def get_config(_cache=[]):
>> >     private = {}
>> >     private['a'] = 1
>> >     private['b'] = 2
>> >     if not _cache:
>> >         class Config(object):
>> >             @property
>> >             def a(self):
>> >                 return private['a']
>> >             @property
>> >             def b(self):
>> >                 return private['b']
>> >         config = Config()
>> >         _cache.append(config)
>> >     else:
>> >         config = _cache[0]
>> >     return config
>> >
>> > >>> c = get_config()
>> > >>> c.a
>> > 1
>> > >>> c.b
>> > 2
>> > >>> c.a = 10
>> > Traceback (most recent call last):
>> >   File "<string>", line 1, in <fragment>
>> > AttributeError: can't set attribute
>> > >>> dir(c)
>> > ['__class__', '__delattr__', '__dict__', '__doc__', '__format__',
>> > '__getattribute__', '__hash__', '__init__', '__module__', '__new__',
>> > '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
>> > '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b']
>> > >>> d = get_config()
>> > >>> d is c
>> > True
>> >
>> > I'm not really asking 'is it a good idea' but just 'does this work'?
>> > It seems to work to me, and is certainly 'good enough' in the sense
>> > that it should be impossible to accidentally change the variables of
>> > c.
>> >
>> > But is it possible to change the value of c.a or c.b with standard
>> > python, without resorting to ctypes level manipulation?
>>
>> It's not easy, but it can be done by introspecting the property object
>> you created and munging the closed-over dictionary object:
>>
>>    >>> c = get_config()
>>    >>> c.a
>>    1
>>    >>> c.__class__.__dict__['a'].fget.func_closure[0].cell_contents['a'] = 7
>>    >>> c.a
>>    7

Ah!  That is what I was looking for.

> Heh, and of course I miss the even more obvious trick of just clobbering
> the property with something else:
>
>  >>> c.a
>  1
>  >>> setattr(c.__class__,"a",7)
>  >>> c.a
>  7

Well, that is just cheating!  :-)

Anyway, thanks for that.  I still think it is 'good enough' for those
cases where private variables are 'required'.  In both cases one has
to go out of ones way to modify the attribute.  OTOH, I guess it
depends on what the use case is.  If it is for storing a secret
password that no other part of the system should have access to, then
perhaps not 'good enough' at all.

Cheers,

Rasjid.



More information about the Python-list mailing list