switching an instance variable between a property and a normal value
Steven Bethard
steven.bethard at gmail.com
Fri Jan 7 18:49:01 EST 2005
Robert Brewer wrote:
> Steven Bethard wrote:
>
>>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.
>>
>>The best option I guess is to rewrite this with a
>>_getdefault() function instead of a property:
>>
>>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.
>
>
> It seems to me like you were using the property as a glorified flag.
> Just use a flag.
>
> ftypes = ('BuiltinFunctionType', 'BuiltinMethodType',
> 'FunctionType', 'GeneratorType', 'LambdaType',
> 'MethodType', 'UnboundMethodType',)
>
> class D(dict):
> def __init__(self):
> self._default = None
> self._call_default = False
> def __getitem__(self, key):
> if not key in self:
> if self._call_default:
> self[key] = self._default()
> else:
> self[key] = self._default
> return dict.__getitem__(self, key)
> def setdefaultvalue(self, value):
> self._default = value
> self._call_default = isinstance(value, ftypes)
>
> ...or:
>
> def setdefaultvalue(self, value, call_callables=True):
> self._default = value
> self._call_default = callable(value) and call_callables
Well, the right solution using a flag for the particular behavior I was
looking for would have to look something like:
class D(dict):
def __init__(self):
self._default = None
self._call = False
def __getitem__(self, key):
if not key in self:
if self._call:
func, args, kwds = self._default
self[key] = func(*args, **kwds)
else:
self[key] = self._default
return dict.__getitem__(self, key)
def setdefault(self, value, call=False, *args, **kwds):
if call:
self._default = value, args, kwds
else:
self._default = value
self._call = call
where I also accept *args and **kwds when the default value is to be
called. It's certainly doable with a flag, but note that I have to
check the flag every time in both __getitem__ and setdefault. It'd
minimize redundancy a bit if I only had to check it in one place. Guess
I could do something like:
class D(dict):
def __init__(self):
self._default = None
self._call_default = False
def __getitem__(self, key):
if not key in self:
self[key] = self._default()
return dict.__getitem__(self, key)
def setdefault(self, value, call=False, *args, **kwds):
if call:
def caller():
return value(*args, **kwds)
else:
def caller():
return value
self._default = caller
Then I only have to test call when setdefault is called. Not sure I
like this any better though...
Steve
P.S. The reason I had two functions, setdefaultvalue and
setdefaultfunction has to do with argument parsing for
setdefaultfunction. Note that
def setdefault(self, value, call=False, *args, **kwds):
...
means that you can't call functions with keyword arguments 'value' or
'call'. That means I have to rewrite this function as something like
def setdefault(*args, **kwds):
self = args[0]
value = args[1]
call = ???
...
The problem is, if 'call' is a keyword argument, I don't know whether it
was intended as one of the function arguments or as an argument to
setdefault.
If setdefaultvalue and setdefaultfunction are two separate methods, I
don't run into this problem.
More information about the Python-list
mailing list