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.
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to