How to clone or copy a set in Python?
Asked Answered
O

2

71

For copying a list: shallow_copy_of_list = old_list[:].

For copying a dict: shallow_copy_of_dict = dict(old_dict).

But for a set, I was worried that a similar thing wouldn't work, because saying new_set = set(old_set) would give a set of a set?

But it does work. So I'm posting the question and answer here for reference. In case anyone else has the same confusion.

Oxidate answered 21/4, 2014 at 16:1 Comment(0)
O
87

Both of these will give a duplicate of a set:

shallow_copy_of_set = set(old_set)

Or:

shallow_copy_of_set = old_set.copy() #Which is more readable.

The reason that the first way above doesn't give a set of a set, is that the proper syntax for that would be set([old_set]). Which wouldn't work, because sets can't be elements in other sets, because they are unhashable by virtue of being mutable. However, this isn't true for frozensets, so e.g. frozenset(frozenset(frozenset([1,2,3]))) == frozenset([1, 2, 3]).

So a rule of thumb for replicating any of instance of the basic data structures in Python (lists, dict, set, frozenset, string):

a2 = list(a)      #a is a list
b2 = set(b)       #b is a set
c2 = dict(c)      #c is a dict
d2 = frozenset(d) #d is a frozenset
e2 = str(e)       #e is a string
#All of the above give a (shallow) copy.

So, if x is either of those types, then

shallow_copy_of_x = type(x)(x) #Highly unreadable! But economical.

Note that only dict, set and frozenset have the built-in copy() method. It would probably be a good idea that lists and strings had a copy() method too, for uniformity and readability. But they don't, at least in Python 2.7.3 which I'm testing with.

Oxidate answered 21/4, 2014 at 16:1 Comment(1)
Note: In 3.3+, lists have a .copy() method. str does not, but it also doesn't need one; it's immutable, so copying is meaningless (for general sequence types, you can slice with [:], which works on str, it's just pointless). If you really need to handle shallow-copying arbitrary types (silently reusing the existing object for immutable types like str), you'd just use the copy module, and do shallow_copy_of_x = copy.copy(x) (which is significantly clearer than type(x)(x), and handles types where the constructor doesn't accept an instance of the class).Rombert
E
12

Besides the type(x)(x) hack, you can import copy module to make either shallow copy or deep copy:

In [29]: d={1: [2,3]}

In [30]: sd=copy.copy(d)
    ...: sd[1][0]=321
    ...: print d
{1: [321, 3]}

In [31]: dd=copy.deepcopy(d)
    ...: dd[1][0]=987
    ...: print dd, d
{1: [987, 3]} {1: [321, 3]}

From the docstring:

Definition: copy.copy(x)
Docstring:
Shallow copy operation on arbitrary Python objects.
Escribe answered 21/4, 2014 at 16:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.