2

I have a dictionary where the keys are letters, and the values are arrays. I want to extract one of the arrays, and then pop a value from it, without changing the dictionary.

mydict = {'a': ['apple', 'avocado'], 
          'b': ['banana', 'berry'], 
          'c': ['carrot', 'cucumber']}

fruits = mydict['a']
fruits.pop(0)

When I print the dict I then get:

>> {'a': ['avocado'], 'b': ['banana', 'berry'], 'c': ['carrot', 'cucumber']}

How do I get a copy of the list that won't change the dictionary when I pop from it?

Andrew Einhorn
  • 741
  • 8
  • 23
  • Also here's a working [repl.it project](https://repl.it/@HarunYlmaz/GleamingGreenRhombus) I just created. You just need to create a `list` from `mydict['a']` as `fruits = list(mydict['a'])` – Harun Yilmaz Jul 14 '20 at 12:59
  • 1
    `fruits = mydict['a'].copy()`. Or, even better, `fruits = mydict['a'][1:]` to get all but the first element. – swenzel Jul 14 '20 at 13:09

5 Answers5

3

Ust the .copy() attribute when assigning the fruit variable.

>>> mydict = {'a': ['apple', 'avocado'], 
              'b': ['banana', 'berry'], 
              'c': ['carrot', 'cucumber']}

>>> fruits = mydict['a'].copy()
>>> fruits.pop(0)

This will give the following results

>>> mydict

{'a': ['apple', 'avocado'],
 'b': ['banana', 'berry'],
 'c': ['carrot', 'cucumber']}

>>> fruits

['avocado']
Desi Pilla
  • 544
  • 6
  • 20
  • 1
    Cool, thanks for this. I didn't realise my question was actually about list assignment and not dictionaries. Now that I see this, I realise that fruits = mydict['a'] doesn't create a new list, it just points to the original list (inside the dict). And your .copy() solves this for me by creating a new list. – Andrew Einhorn Jul 14 '20 at 14:24
2

The = operator creates a new variable or data structure, but it basically points to the same object as before. So using the = operator won't work.

You can use the list.copy() method which returns a shallow copy of the list in the dictionary. Modifying this list will not modify the original dictionary.

mydict = {'a': ['apple', 'avocado'], 
          'b': ['banana', 'berry'], 
          'c': ['carrot', 'cucumber']}

fruits = mydict['a'].copy()
fruits.pop(0)

print(fruits) # returns ['avocado']
print(mydict) # returns {'a': ['apple', 'avocado'] ...}

Alternatively, use the Python copy module's copy() or deepcopy() method which will both work.

import copy

mydict = {'a': ['apple', 'avocado'], 
          'b': ['banana', 'berry'], 
          'c': ['carrot', 'cucumber']}

fruits = copy.copy(mydict['a']) # or copy.deepcopy(mydict['a'])
fruits.pop(0)

print(fruits) # returns ['avocado']
print(mydict) # returns {'a': ['apple', 'avocado'] ...}

The distinction between shallow (the copy() method) and deep copying (the deepcopy() method) is important but does not really apply in this case, because you are not copying a nested data structure (your dictionary) but only a list within that dictionary.

For example, shallow copying the dict and modifying the nested list also modifies the original:

import copy

mydict = {'a': ['apple', 'avocado'], 
          'b': ['banana', 'berry'], 
          'c': ['carrot', 'cucumber']}

fruits = copy.copy(mydict)
fruits['a'].append('apricot') # also changes mydict

print(fruits) # returns {'a': ['apple', 'avocado', 'apricot'] ...}
print(mydict) # also returns {'a': ['apple', 'avocado', 'apricot'] ...}

While deep copying does not:

import copy

mydict = {'a': ['apple', 'avocado'], 
          'b': ['banana', 'berry'], 
          'c': ['carrot', 'cucumber']}

fruits = copy.deepcopy(mydict)
fruits['a'].append('apricot') # also changes mydict

print(fruits) # returns {'a': ['apple', 'avocado', 'apricot'] ...}
print(mydict) # returns {'a': ['apple', 'avocado'] ...}

From the Python 3 docs on the copy module:

The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):

  • A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.

  • A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

Leo Qi
  • 557
  • 5
  • 13
  • 1
    Thanks for the comprehensive and clear answer, this is awesome. I marked the shorter version from Desi Pilla as the answer because deepcopy is not required for this question. But I appreciate the full explanation. – Andrew Einhorn Jul 14 '20 at 14:30
0

Deep copy:

import copy
fruits = copy.deepcopy(my_dict["a"])

Shallow copy:

import copy
fruits = copy.copy(my_dict["a"])
fruits = my_dict["a"].copy()
fruits = list(my_dict["a"])

As all your elements are of type str, shallow copy the lists. str objects are immutable, so their internal state cannot be modified. Whenever you "modify" a str, you actually just make a copy.

More details on deep copying in Python

0

If you're trying to get a specific value (in this case "avocado"), and you want it in list form, you just surround the expression in square brackets and it becomes a list like so:

fruits = [mydict["a"][1]]
SSardorf
  • 16
  • 2
-4

Instead of using pop use index to get the item. It will leave your array inside in the dict intact.

fruit = mydict['a'][0]