[Tutor] Lists of duplicates

Steven D'Aprano steve at pearwood.info
Thu Mar 9 09:07:28 EST 2017

On Wed, Mar 08, 2017 at 08:29:19PM -0800, Alex Kleider wrote:

> Things like this can usually be broken down into their component parts 
> but I've been unsuccessful doing so:
> def f(lst):
>     res = {}
>     for item in lst:
>         method_res = res.setdefault(item, [])
>         res.method_res.append(item)
> #       res.setdefault(item,[]).append(item)
>     return list(res.values())
>     res.method_res.append(item)
> AttributeError: 'dict' object has no attribute 'method_res'
> Python must be doing some trickery behind the scenes.

Why do you say that? I'm not sure what result you expected, or what you 
are trying to do, but you have:

    res  # a dict

No surprises that this fails with AttributeError. Dicts do not have an 
attribute or method called "method_res".

Perhaps you meant to write:

    # not this
    # res.method_res.append( ... )

    # this instead
    method_res.append( ... )

although part of the confusion is that "method_res" is a poorly chosen 
name. It isn't a method, it is a list.

Perhaps it will help if I demonstrate what is going on with setdefault:

py> mydict = {}
py> alist = mydict.setdefault(1, [])
py> alist
py> mydict
{1: []}

So when you call setdefault on a dict, if the key is missing, it does 
two things:

- it sets the key to the given default value;
- and then it returns that same value.

We could write our own setdefault method like this:

def setdefault(self, key, default):
    if key in self:  # self is the dictionary itself
        return self[key]
        self[key] = default
        return default

Notice that default is used twice: it is the *same object*, not a fresh 

py> id(alist), id(mydict[1])
(3080262860, 3080262860)

So if default is a mutable list, changes to that list will show up 
in two places:

py> alist.append(99)
py> mydict
{1: [99]}


More information about the Tutor mailing list