Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #102926 > unrolled thread

How to properly override the default factory of defaultdict?

Started byHerman <sorsorday@gmail.com>
First post2016-02-14 16:17 -0800
Last post2016-02-15 21:28 +1300
Articles 3 — 3 participants

Back to article view | Back to comp.lang.python


Contents

  How to properly override the default factory of defaultdict? Herman <sorsorday@gmail.com> - 2016-02-14 16:17 -0800
    Re: How to properly override the default factory of defaultdict? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2016-02-15 14:56 +1100
    Re: How to properly override the default factory of defaultdict? Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2016-02-15 21:28 +1300

#102926 — How to properly override the default factory of defaultdict?

FromHerman <sorsorday@gmail.com>
Date2016-02-14 16:17 -0800
SubjectHow to properly override the default factory of defaultdict?
Message-ID<mailman.122.1455495511.22075.python-list@python.org>
I want to pass in the key to the default_factory of defaultdict and I found
that defaultdict somehow can intercept my call to dict.__getitem__(self,
key), so my class's __getitem__ have to catch a TypeError instead instead
of KeyError. The following class is my code:

class DefaultDictWithEnhancedFactory(defaultdict):
    """Just like the standard python collections.dict,
    but the default_factory takes the missing key as argument.

    Args:
        default_factory: A function that takes the missing key as the
argument
        and return a value for the missing key.
        *a: arguments passing to the defaultdict constructor
        **kw: keyword arguments passing to the defaultdict constructor
    """
    def __init__(self, default_factory, *a, **kw):
        defaultdict.__init__(self, default_factory, *a, **kw)

    def __getitem__(self, key):
        try:
            return dict.__getitem__(self, key)
        except KeyError:
            # Normally, you would expect this line to be
            # called for missing keys...
            return self.default_factory(key)
        except TypeError as ex:
            # However, this is actually getting called
            # because for some reason, defaultdict still
            # intercepts the __getitem__ call and raises:
            # TypeError: <lambda>() takes exactly 1 argument (0 given)
            # So we have to catch that instead...
            if "lambda" in str(ex):
                return self.default_factory(key)

[toc] | [next] | [standalone]


#102934

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2016-02-15 14:56 +1100
Message-ID<56c14c74$0$1500$c3e8da3$5496439d@news.astraweb.com>
In reply to#102926
On Monday 15 February 2016 11:17, Herman wrote:

> I want to pass in the key to the default_factory of defaultdict 

Just use a regular dict and define __missing__:

class MyDefaultDict(dict):
    def __missing__(self, key):
        return "We gotcha key %r right here!" % key


If you want a per-instance __missing__, do something like this:


class MyDefaultDict(dict):
    def __init__(self, factory):
        self._factory = factory
    def __missing__(self, key):
        return self._factory(self, key)


d = MyDefaultDict(lambda self, key: ...)


-- 
Steve

[toc] | [prev] | [next] | [standalone]


#102953

FromGregory Ewing <greg.ewing@canterbury.ac.nz>
Date2016-02-15 21:28 +1300
Message-ID<didgheFteu2U1@mid.individual.net>
In reply to#102926
Herman wrote:
> I want to pass in the key to the default_factory of defaultdict and I found
> that defaultdict somehow can intercept my call to dict.__getitem__(self,
> key),

What's happening here is that defaultdict doesn't actually
override __getitem__ at all. Instead, it overrides __missing__,
which gets called by the standard dict's __getitem__ for a
missing key.

As Steven said, you don't need a defaultdict here at all,
just a dict subclass that defines __missing__ the way you
want.

-- 
Greg

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web