Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create copies of a python object that are not linked to original object?

(Using Python 2.7)

I am trying to create replicates of a template object to be filled in later. For simplicity I tried to do it like this:

template={'thing1':'','thing2':'','thing3':''}
for number in some_list:
    pile[number]=template

but later on when I did this:

pile[1]['thing1']='blahblah'

it also results in:

print pile[2]['thing1']
'blahblah'
print template['thing1']
'blahblah'

What I want is for

pile[1]['thing1']='blahblah'

to leave pile[2] alone, so that

print pile[2]['thing1']
''

And I know that the problem is that when I say

pile[number]=template

it means that pile[1] IS template, and pile[2] IS template. (This I only just fully realized today while working on this...and I repeated it to myself several times out loud as the realization and its implications slowly sank in... That's how python works, eh? I feel like I just joined the python club. I started out with MATLAB so don't be too rough on me.)

So I imagine there might be two ways to go about this - one involves some kind of replication of objects that are not linked to the original, or something like that, and is probably really simple and obvious. And maybe there is another way to do it that is specific to dicts, like initializing the keys or something. I'm mostly interested in the first kind of answer, because that would help round out my understanding of how python works, but the second kind of answer would be nice too. Thanks :)

like image 527
andy Avatar asked Oct 15 '25 04:10

andy


2 Answers

The simplest way to make a shallow copy of a dictionary is to use the dict's copy method:

In [1]: template = {'thing1': '', 'thing2': '', 'thing3': ''}

In [2]: apile = template.copy()

In [3]: apile['thing1'] = 1

In [4]: apile
Out[4]: {'thing1': 1, 'thing2': '', 'thing3': ''}

In [5]: template
Out[5]: {'thing1': '', 'thing2': '', 'thing3': ''}

 

To make a shallow copy of a list, you can take a slice of the entire list:

copied_list = original_list[:]

 

If you need to clone other things, or if you need a deep copy of a dict of dicts (or a list of dicts, or other mutable objects), you should use the copy module: http://docs.python.org/2/library/copy.html

copy.copy(x)

Return a shallow copy of x.

copy.deepcopy(x)

Return a deep copy of x.

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.

 

About your second way: sure, you can create a dict out of another dict, and it will be a copy:

In [23]: p = dict(template)

In [24]: p['thing1'] = 1

In [25]: template
Out[25]: {'thing1': '', 'thing2': '', 'thing3': ''}

In [26]: p
Out[26]: {'thing1': 1, 'thing2': '', 'thing3': ''}
like image 89
Pavel Anossov Avatar answered Oct 17 '25 18:10

Pavel Anossov


Here is my initial solution

import copy

template = {1:''}
d = {}

for n in xrange(10):
    d[n] = copy.deepcopy(template)

however I like Pavel's better.

like image 22
John Avatar answered Oct 17 '25 18:10

John



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!