switching an instance variable between a property and a normal value

Steven Bethard steven.bethard at gmail.com
Fri Jan 7 17:35:21 EST 2005


Robert Brewer wrote:
> Steven Bethard wrote:
> 
>>I'd like to be able to have an instance variable that can 
>>sometimes be 
>>accessed as a property, and sometimes as a regular value, 
>>e.g. something 
>>like:
> 
> ...
> 
>>py> c.x is c.x # I'd like this to be False
> 
> 
> You'd like 'c.x is c.x' to be FALSE? You can't be serious. Must be a
> typo.

Hmm... maybe I better give the larger context.  The short answer is no, 
I'm serious.

I'm playing around with a mapping type that uses setdefault as suggested 
in http://www.python.org/moin/Python3_2e0Suggestions.  The default value 
for a missing key is either a simple value, or a value generated from a 
function.  If it's generated from the function, it should be generated 
new each time so that, for example, if the default is an empty list, 
d[1] and d[2] don't access the same list.  This is why 'c.x is c.x' 
should be False if I'm using the function.

Some more context:

Before I added the ability to use a function, my code looked something like:

py> class D(dict):
...     def __init__(self):
...         self._default = None
...     def __getitem__(self, key):
...         if not key in self:
...             self[key] = self._default
...         return dict.__getitem__(self, key)
...     def setdefaultvalue(self, value):
...         self._default = value
...
py> d = D()
py> d[0]
py> d.setdefaultvalue(0)
py> d[1]
0
py> d[2] += 1
py> d
{0: None, 1: 0, 2: 1}

To add the ability to use a function to create the default value, it 
would have been nice to leave basically the same code I already had and 
do something like:

py> class D(dict):
...     def __init__(self):
...         self._default = None
...     def __getitem__(self, key):
...         if not key in self:
...             self[key] = self._default
...         return dict.__getitem__(self, key)
...     def setdefaultvalue(self, value):
...         self._default = value
...     def setdefaultfunction(self, func, *args, **kwds):
...         self._func, self._args, self._kwds = func, args, kwds
...         self._default = D._defaultfunc
...     def _get(self):
...         return self._func(*self._args, **self._kwds)
...     _defaultfunc = property(_get)
...

Of course, this doesn't work for the reasons that I discussed, but the 
idea would be that D would use a regular attribute when a simple value 
was needed, and a property when a value had to be generated by a 
function each time.

The best option I guess is to rewrite this with a _getdefault() function 
instead of a property:

py> class D(dict):
...     _undefined = object()
...     def __init__(self):
...         self._value = None
...         self._func = self._undefined
...     def __getitem__(self, key):
...         if not key in self:
...             self[key] = self.getdefault()
...         return dict.__getitem__(self, key)
...     def getdefault(self):
...         if self._value is not self._undefined:
...             return self._value
...         if self._func is not self._undefined:
...             return self._func(*self._args, **self._kwds)
...     def setdefaultvalue(self, value):
...         self._value = value
...         self._func = self._undefined
...     def setdefaultfunction(self, func, *args, **kwds):
...         self._func, self._args, self._kwds = func, args, kwds
...         self._value = self._undefined
...

But I was hoping to avoid having two separate attributes (self._value 
and self._func) when only one should have a value at any given time.

Steve





More information about the Python-list mailing list