Tom Baker
Tom Baker

Reputation: 693

References to mutables (e.g., lists) as values in Python dictionaries - what is best practice?

It is possible to map a dictionary key to a value that is a reference to a mutable object, such as a list. Such a list object can be changed by invoking a list method on the reference, and the changes will be reflected in the dictionary. This is discussed in:

My question

Is it a good idea to map a dictionary key to the reference of a mutable object as opposed to mapping the key to an unnamed value?

In other words, it is better to create a dictionary with:

In [74]: x = {'a': somelist}

or:

In [74]: x = {'a': somelist[:]}

And is it better to change a dictionary value though citing that value by reference, e.g.:

In [77]: somelist.remove('apples')

or by its dictionary index:

In [77]: x['a'].remove('apples')

Discussion and research

A reference provides a nice handle that can improve the readability of, say, a function. As far as I can tell, however, the fact that a dictionary value was originally bound to a reference is lost once the value is created; one cannot see this fact when displaying a dictionary.

On the other hand, I am not sure this matters, because the reference and the value are the same object, and if one deletes the reference, the value object itself remains.

As I see it:

In [73]: somelist = ['apples', 'oranges', 'lemons', 'tangerines']
In [74]: x = {'a': somelist}
In [75]: x
Out[75]: {'a': ['apples', 'oranges', 'lemons', 'tangerines']}

In dictionary x, key 'a' maps to value somelist, though I do not see a way to verify that the value is associated with the reference somelist.

In [76]: x['a'] is somelist
Out[76]: True

This confirms that the list I see as the value is the same as the object pointed to by somelist.

In [77]: x['a'].remove('apples')
In [78]: x
Out[78]: {'a': ['oranges', 'lemons', 'tangerines']}

Since the value of 'a' in dictionary x is a list, I can remove an item from the list using the list method remove on object x['a'].

In [79]: somelist.remove('lemons')
In [80]: x
Out[80]: {'a': ['oranges', 'tangerines']}

Alternatively, I can use the method remove on object somelist.

In [81]: del somelist

I can delete the reference to the list, but the list object itself remains as the value associated with key a.

In [82]: x['a'].remove('oranges')

In [83]: x
Out[83]: {'a': ['tangerines']}

Upvotes: 10

Views: 185

Answers (2)

BrenBarn
BrenBarn

Reputation: 251428

As I understand your question, the answer is that it depends what you want to do. If you want to set the dictionary value to an independent copy of some other value, then make a copy. If you want to set it to the same object, then don't make a copy.

In some cases you may want the dictionary to refer to the same object as other references, because this allows the dictionary to "see" changes to that object. In some cases you may want the dictionary to have its own copy, because you don't want other code that changes the object to affect your dictionary. It just depends on what the mutable object is and how your code as a whole is using it.

Upvotes: 4

jme
jme

Reputation: 20735

First, it is fine to use mutable values in a dictionary. This isn't an anti-pattern. If you don't need to copy a list, then don't. It's extra work, so be lazy and don't do it.

Second, while there are instances in which I have two references to a mutable object laying around, these seem to be rare. I'd argue that you want to minimize the number of these cases, because having two different names in the same scope pointing to the same object can potentially be confusing. But if you have somelist and x['a'] pointing to the same object, use whichever is clearest. The former will be faster, but not by much, and won't be a huge speed improvement unless written in a tight loop. So go with what reads the best.

Upvotes: 0

Related Questions