Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Deeper copy than deepcopy

3 views
Skip to first unread message

Scott Pakin

unread,
Oct 27, 2009, 4:01:52 PM10/27/09
to
copy.deepcopy apparently preserves multiple references to the same object:

$ python
Python 2.5.2 (r252:60911, Jan 4 2009, 17:40:26)
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import copy
>>> d = [1,2,3]
>>> r = copy.deepcopy([d]*3)
>>> r
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
>>> r[1][2] = 999
>>> d
[1, 2, 3]
>>> r
[[1, 2, 999], [1, 2, 999], [1, 2, 999]]
>>>

I wanted to wind up with r being [[1, 2, 3], [1, 2, 999], [1, 2, 3]].
What's the right way to construct r as a list of *independent* d lists?

Thanks,
-- Scott

Cameron Simpson

unread,
Oct 27, 2009, 5:23:54 PM10/27/09
to Scott Pakin, pytho...@python.org

Well, you would need to write your own. But consider this:

x = [1, 2]
x.append(x)

Your deepercopy() function will explode.

Probably the best method is to pre-munge the list you pass to deepcopy:

d = [1,2,3]
d3 = [d]*3
# pre-copy the multiple references
d3deeper = [ list(d3i) for d3i in d3 ]
r = copy.deepcopy(d3deeper)

You can see this requires special knowledge of the structure you're
copying though.
--
Cameron Simpson <c...@zip.com.au> DoD#743
http://www.cskk.ezoshosting.com/cs/

The mere existence of a problem is no proof of the existence of a solution.
- Yiddish Proverb

Cameron Simpson

unread,
Oct 27, 2009, 5:43:09 PM10/27/09
to Scott Pakin, pytho...@python.org
On 28Oct2009 08:23, I wrote:
| | I wanted to wind up with r being [[1, 2, 3], [1, 2, 999], [1, 2, 3]].
| | What's the right way to construct r as a list of *independent* d lists?
|
| Well, you would need to write your own. But consider this:
| x = [1, 2]
| x.append(x)
| Your deepercopy() function will explode.

I've thought of a comprimise that would work automatically: deepcopy
tracks all the objects in the structure and replicates their multiple
uses. For your purposes, you could write a version of deepcopy that did
a depth-first recursion and only tracked the ancestor objects.

That way the above x.append(x) recursive list would not duplicate the
inner "x", but an "x" in two subbranches of a structure _would_ be
replicated i.e. this:

x = [1,2]
y = [x, x]

would get two independent "x"s.

However, it would still mean a recursive structure would get non-independent
"x"s. Which is necessary to avoid an infinite copy but breaks your
requirement.

Every technical corrigendum is met by an equally troublesome new defect report.
- Norman Diamond <dia...@jit.dec.com>

Gary Herron

unread,
Oct 27, 2009, 6:16:15 PM10/27/09
to pytho...@python.org

Try this:

>>>
>>> d = [1,2,3]
>>> r = [[x for x in d] for i in range(3)]


>>> r[1][2] = 999

>>> r


[[1, 2, 3], [1, 2, 999], [1, 2, 3]]

Gary Herron

Steven D'Aprano

unread,
Oct 27, 2009, 8:22:03 PM10/27/09
to
On Tue, 27 Oct 2009 15:16:15 -0700, Gary Herron wrote:

> Try this:
>
>
> >>> d = [1,2,3]
> >>> r = [[x for x in d] for i in range(3)]
> >>> r[1][2] = 999
> >>> r
> [[1, 2, 3], [1, 2, 999], [1, 2, 3]]


[x for x in d] is better written as d[:]


--
Steven

Scott Pakin

unread,
Oct 28, 2009, 12:31:51 PM10/28/09
to
Thanks everyone! The list-comprehension approach should work in my case
as I know a priori that my data structure is finite. Still, it'd be
awfully convenient for Python's copy module to offer a copy.deepercopy
function -- even if it comes with the caveat that it will explode if
given a data structure with backlinks.

Regards,
-- Scott

0 new messages