set.copy()
set.copy() set · Updated March 15, 2026 · Set Methods The .copy() method returns a shallow copy of a set. The returned set contains references to the same elements as the original, not deep copies of them. Since set elements are typically immutable (numbers, strings, tuples), this distinction rarely matters in practice.
Syntax
set.copy()
This method takes no parameters.
Examples
Basic usage
Create a copy of a set:
original = {1, 2, 3}
copied = original.copy()
print(copied)
# {1, 2, 3}
print(original is copied)
# False # Different objects
Independent modifications
Modifying the copy does not affect the original:
fruits = {"apple", "banana", "cherry"}
fruits_copy = fruits.copy()
fruits_copy.add("orange")
print(fruits)
# {"apple", "banana", "cherry"}
print(fruits_copy)
# {"apple", "banana", "cherry", "orange"}
Copy vs constructor
The .copy() method and the set constructor produce equivalent results:
source = {1, 2, 3}
copy_method = source.copy()
copy_constructor = set(source)
print(copy_method == copy_constructor)
# True
The .copy() method is slightly more readable and explicit about intent.
Preserving set type
Both approaches preserve the set type:
numbers = {10, 20, 30}
copied = numbers.copy()
print(type(copied))
# <class 'set'>
Note that .copy() does not work on frozensets — use the frozenset constructor instead:
frozen = frozenset([1, 2, 3])
copied = set(frozen) # Convert to regular set
print(copied)
# {1, 2, 3}
Common Patterns
Passing a set to a function without mutation
Avoid unintended modifications by copying before passing:
def process_set(s):
s.add(4) # Modifies the set
return s
original = {1, 2, 3}
# Safe - original is unchanged
result = process_set(original.copy())
print(original)
# {1, 2, 3}
print(result)
# {1, 2, 3, 4}
# Unsafe - original is modified
result = process_set(original)
print(original)
# {1, 2, 3, 4} # Changed!
Creating a modifiable version from frozenset
Convert an immutable frozenset to a regular set:
immutable = frozenset(["a", "b", "c"])
mutable = immutable.copy() # Still a frozenset!
# TypeError: 'frozenset' object is not callable
# Correct approach
mutable = set(immutable)
mutable.add("d")
print(mutable)
# {"a", "b", "c", "d"}
Backup before batch operations
Create a backup before performing destructive operations:
data = {1, 2, 3, 4, 5}
backup = data.copy()
# Perform operations
data.discard(1)
data.discard(2)
data.difference_update({3})
print(data)
# {4, 5}
# Restore if needed
if some_condition:
data = backup
This pattern is useful when you need to explore different branches of data processing.
Set difference for rollback
Compare the copy with the modified set to track changes:
current = {1, 2, 3, 4, 5}
original_snapshot = current.copy()
current.discard(2)
current.discard(4)
added = current - original_snapshot
removed = original_snapshot - current
print(f"Removed: {removed}") # {2, 4}
print(f"Added: {added}") # set()
Deep Copy Consideration
For sets containing mutable objects, you might need a deep copy:
import copy
# Shallow copy - nested lists share references
sets_with_lists = {[1, 2], [3, 4]}
shallow = sets_with_lists.copy()
shallow[0].append(99)
print(sets_with_lists) # [[1, 2, 99], [3, 4]] # Original modified!
# Deep copy - truly independent
deep = copy.deepcopy(sets_with_lists)
deep[0].append(100)
print(sets_with_lists) # [[1, 2, 99], [3, 4]] # Unchanged
However, this is rare since set elements should be hashable (typically immutable).
Performance
The .copy() method has:
- Time complexity: O(n) where n is the number of elements
- Space complexity: O(n) for the new set
The operation must iterate through all elements to create the new set. For large sets, consider whether you actually need a full copy or can use a different approach.
See Also
- set::set — the set constructor
- set::set.clear — remove all elements from a set
- dict::dict.copy — similar method for dictionaries
- list::list.copy — similar method for lists