How-To: Copy a Dictionary or List in Python

My goals with this post are to show how to copy a dictionary or list in Python, the different ways to perform the copies, and the differences between them.

CONTENTS

  1. BACKGROUND
  2. COPYING EXAMPLES
    1. Example of Variable Assignment
    2. Shallow Copy Without Nested Objects Example
    3. Shallow Copy With Nested Objects Example
    4. Deep Copy Example

BACKGROUND

I am writing this post due to some issues I came across recently after copying dictionaries in Python. My issues occurred when I edited items in the copy of a dictionary. I expected the changes to only appear in the copy, however the changes also appeared in the original dictionary.

The short explanation of why this happened is that it was due to:

  • how dictionaries (and lists) are stored in Python
  • the fact that I only did a limited/shallow copy of the original dictionary
  • I made changes to nested dictionaries contained inside of the original dictionary, however, the copy operation I performed did not copy the nested dictionaries to the copied version of the original dictionary.

COPYING EXAMPLES

Please note: I will be showing examples with dictionaries, however, the same concepts apply to lists in Python.

Example of Variable Assignment

The general first assumption of how to copy a dictionary is to just set a new variable equal to a variable containing a dictionary. This actually does not work as one would expect.

Shallow copy of a dictionary where changes to one dictionary affect the other dictionary
Shallow copy of a dictionary, where changes effect both dictionaries

Notice that by changing dict_b, we also make the same change to dict_a. This happens because a variable containing a dictionary, list, or object in Python actually just contains a pointer to that dictionary, list, or object. Therefore, dict_a actually contains a pointer to the address of a dictionary object. So, when we set dict_b equal to dict_a, we are just assigning the same pointer to dict_b, so now dict_b also points to the same dictionary object.

# actual_dict is stored in memory address A1

dict_a = A1 -> actual_dict
dict_b = dict_a
dict_b = A1 -> actual_dict

To actually copy the dictionary, we want to perform an operation that will create a copy of what we call “actual_dict” above. Below, we illustrate a couple of ways to make copies of a dictionary.

Shallow Copy Without Nested Objects Example

We may use either dict.copy() or we may pass a dictionary as a parameter to the dict() function in order to perform a simple/shallow copy of a dictionary.

Shallow copy of a dictionary where changes to one dictionary affect the other dictionary
Shallow copy of a dictionary; changes to basic elements in one dictionary only effect that dictionary

Now we can see that changes we make to one dictionary do not appear in another dictionary. This holds true so long as there are no objects, such as dictionaries or lists, as values within our original dictionary before we copy it.

Shallow Copy With Nested Objects Example

Here is an example of doing a normal/shallow copy of a dictionary when it has nested objects, such as dictionaries or lists within it.

Shallow copy of a dictionary with a nested dictionary inside, where changes to the nested dictionary in one outer dictionary affect the other outer dictionary
Shallow copy of a dictionary with nested dictionary; changes to nested dictionary in one outer dictionary are also reflected in the other outer dictionary

Now we observe that when adding a value to the nested dictionary, the change is shown in both dict_a and dict_b. Adding a simple key/value pair in dict_b, however, only affects dict_b. This occurs because the value of key “2” is stored as a pointer to a dictionary object. So, when we do our shallow copy, just the pointer (address of the nested dictionary object) is copied. Therefore, when we make changes to it from either dict_a or dict_b, we are changing the same object.

# actual_dict is stored in memory address A1
# original_dict is stored in memory address B1
# copied_dict is stored in memory address C1

dict_a = B1 -> original_dict
dict_a["2"] = A1 -> actual_dict
dict_b = dict_a.copy()
dict_b = C1 -> copied_dict
dict_b["2"] = A1 -> actual_dict

If we want to be able to make a full copy of a dictionary, including all nested objects, then we need to import the copy module and use the deepcopy() method.

Deep Copy Example

Deep copy of a dictionary with a nested dictionary inside, where changes to the nested dictionary in one outer dictionary only apply to that outer dictionary
Deep copy of a dictionary with nested dictionary; changes to nested dictionary in one outer dictionary only apply to that dictionary and not the other outer dictionary

We can see above that after editing the nested dictionary within dict_b the changes are only reflected in dict_b and not dict_a.

# actual_dict is stored in memory address A1
# original_dict is stored in memory address B1
# copied_dict is stored in memory address C1
# a_copy_of_actual_dict is stored in memory address D1

dict_a = B1 -> original_dict
dict_a["2"] = A1 -> actual_dict
dict_b = dict_a.copy()
dict_b = C1 -> copied_dict
dict_b["2"] = D1 -> a_copy_of_actual_dict

How-To: Watch DVDs on Fedora Linux

The goal of this post is to help you be able to watch DVDs on Fedora Linux. If you are using a different Linux distribution, this method should be able to be applied by altering it to your respective distro.

CONTENTS

  1. BACKGROUND
  2. DIRECTIONS
    1. Install rpmfusion Repository
    2. Install (all the) Codecs
    3. Install DVD Tools/Libraries and VLC Media Player
    4. Install libdvdcss
  3. Wrapping Up
    1. How To Update libdvdcss in the Future

BACKGROUND

I am slowly in the process of getting ready to replace my current “home media PC” (a.k.a my laptop) with a new computer using Fedora. I used my current Fedora desktop to try watching DVDs, and I found that without adding libdvdcss, I was only able to watch some DVDs but not all DVDs (ex: I could not watch Redbox movies). After a bit of digging and key pounding, I can gladly say that I have been able to watch every DVDI have tried so far, including ones that did not work previous to installing libdvdcss.

This specific guide was written using a system running Fedora 21, but this should work for at least Fedora 20 and Fedora 22.

DIRECTIONS

Note: The ‘-y’ option in the dnf command tells dnf to not prompt for confirmation for the installation. If you would like to see exactly what is being installed and be prompted for confirmation before the install begins, then remove the ‘-y’ option from the commands.

Note: All dnf commands can be replaced by using yum instead of dnf. The first command would have to be changed to ‘yum -y localinstall’, but otherwise you can just do a drop-in replacement of yum wherever dnf is used, if you prefer to use yum.

Install rpmfusion Repository

This repository contains extra packages that are not included in the default Fedora repositories, including packages, such as VLC media player, that we will be installing later in this process.

dnf -y install --nogpgcheck http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm

Install (all the) Codecs

It is possible not every one of these codecs is needed, but I had installed all of them to ensure I didn’t miss anything that would get DVD playing working correctly.

dnf -y install gstreamer-ffmpeg gstreamer-plugins-base gstreamer-plugins-good gstreamer-plugins-good-extras gstreamer-plugins-bad gstreamer-plugins-ugly gstreamer-devel gstreamer-plugins-base-devel gstreamer1-libav gstreamer1-plugins-bad-freeworld gstreamer1-plugins-ugly

Install DVD Tools/Libraries and VLC Media Player

Note: You don’t have to install VLC media player if you have another media player that you prefer, however VLC is a great media player with support for a ton of video and audio formats.

dnf -y install libdvdread libdvdnav lsdvd vlc

Install libdvdcss

libdvdcss is a simple library designed for accessing DVDs like a block device without having to bother about the decryption.
libdvdcss basic description from VideoLAN website

More information on libdvdcss and what it does can be found at the following two links:

  1. If not already installed, install git.
    sudo dnf -y install git
  2. Create a directory to clone (download) the libdvdcss Git repository. This can be created most anywhere of your choosing, just make sure to the path in the commands below with the path you chose.
    mkdir ~/bin
  3. Clone (download) the libdvdcss Git repository
    cd ~/bin
    git clone https://code.videolan.org/videolan/libdvdcss.git
  4. Autoreconf, configure, make, and install the libdvdcss library
    cd libdvdcss
    autoreconf -i
    ./configure --prefix=/usr
    make
    sudo make install

Wrapping Up

Watch DVDs on Fedora Linux - Watching the DVD of The Incredibles
Watching the Incredibles with VLC media player on Fedora 21

Hopefully at this point you can watch your DVDs using Fedora. Make sure to keep the libdvdcss library updated; directions on how to do so are listed below.

If you have any questions or comments, then feel free to leave a comment at the bottom of this page.

How To Update libdvdcss in the Future

New versions of libdvdcss will be released and like any piece of software it is good to keep it up to date. Since we did not install it using the package manager (it was not an option at the time of writing), we will need to do a few manual steps to update it.

cd ~/bin/libdvdcss/
make clean
git pull
autoreconf -i
./configure --prefix=/usr
make
sudo make install