How to make a set in Python

Learn how to make a set in Python. This guide covers creation methods, tips, real-world applications, and how to debug common errors.

How to make a set in Python
Published on: 
Fri
Feb 6, 2026
Updated on: 
Mon
Apr 13, 2026
The Replit Team

Python sets are powerful, unordered collections that store unique items. They are essential when you need to remove duplicates from a list or perform fast membership tests.

In this article, you'll learn several techniques to create sets. We'll explore practical tips for their use, examine real-world applications, and provide advice to help you debug common issues with your code.

Creating a simple set

fruits = {"apple", "banana", "cherry"}
print(fruits)
print(type(fruits))--OUTPUT--{'cherry', 'banana', 'apple'}
<class 'set'>

The most direct way to create a set is by using a set literal. You simply wrap your comma-separated items in curly braces {}, as demonstrated with the fruits variable. This method is clean and readable, especially when you're initializing a set with a few known elements.

Notice the output doesn't preserve the original order. This is a fundamental characteristic of sets—they are optimized for checking if an item is present, not for maintaining sequence. The type() function call is a quick check to confirm you've created a set object.

Basic set creation and modification

Creating a set with curly braces is just the beginning; you can also generate them from other collections and alter their contents dynamically as your program runs.

Creating sets from other data structures

numbers_list = [1, 2, 2, 3, 4, 4, 5]
numbers_set = set(numbers_list)
print("Original list:", numbers_list)
print("Set from list:", numbers_set)--OUTPUT--Original list: [1, 2, 2, 3, 4, 4, 5]
Set from list: {1, 2, 3, 4, 5}

The set() constructor is a flexible way to create a set from any iterable, such as a list or a tuple. It processes the elements from the source collection to build a new set, which is especially useful for cleaning up data and is memory-efficient since sets store unique elements without duplication. This technique is central to converting lists to sets.

  • Notice how the duplicate values from numbers_list are gone. The constructor automatically handles de-duplication, a primary reason for this type of conversion.
  • The original numbers_list isn't changed. The set() function returns a new set object, leaving your source data intact.

Adding elements with add() and update()

colors = {"red", "green"}
colors.add("blue")
colors.update(["yellow", "orange"])
print(colors)--OUTPUT--{'red', 'blue', 'yellow', 'orange', 'green'}

You can dynamically modify a set after it's been created. The key is choosing the right method for the job.

  • Use the add() method to insert a single element. If the item already exists, the set simply remains unchanged, preserving its uniqueness.
  • To add multiple items from an iterable like a list, use update(). It efficiently adds all elements from the collection to your set. These methods are the foundation of appending elements to sets.

Removing elements with remove(), discard(), and pop()

animals = {"dog", "cat", "bird", "fish"}
animals.remove("bird")
animals.discard("elephant")
popped = animals.pop()
print("After modifications:", animals)
print("Popped element:", popped)--OUTPUT--After modifications: {'cat', 'dog'}
Popped element: fish

Removing elements from a set requires choosing the right tool for the situation. The main difference between the methods is how they behave when an item isn't found.

  • The remove() method deletes a specific element, but it will raise a KeyError if the item isn't in the set.
  • For a safer option, use discard(). It removes an element if it exists but does nothing if it's absent, preventing your program from crashing.
  • The pop() method removes and returns an arbitrary element. Since sets are unordered, you can't predict which one you'll get.

Advanced set techniques and operations

Moving past the fundamentals, you can write more expressive and efficient code using set comprehensions, immutable frozenset objects, and powerful mathematical operators.

Using set comprehensions

squares = {x**2 for x in range(1, 6)}
even_squares = {x**2 for x in range(1, 11) if x % 2 == 0}
print("Squares:", squares)
print("Even squares:", even_squares)--OUTPUT--Squares: {1, 4, 9, 16, 25}
Even squares: {4, 16, 36, 64, 100}

Set comprehensions offer a concise and readable way to create sets from iterables. They're a Pythonic shortcut that packs a loop and element creation into a single, elegant line of code, similar to how vibe coding lets you create applications through natural language descriptions. This syntax is similar to patterns used when creating lists with list comprehensions.

  • The basic structure, seen in the squares example, applies an expression like x**2 to every item from a source, such as range(1, 6).
  • You can also add a conditional filter. The even_squares set is built by including an if clause to only process elements that meet a specific criterion.

Working with immutable frozenset

regular_set = {"a", "b", "c"}
frozen = frozenset(regular_set)
print(frozen)
fs1 = frozenset([1, 2, 3])
fs2 = frozenset([3, 4, 5])
print(fs1.intersection(fs2))--OUTPUT--frozenset({'c', 'b', 'a'})
frozenset({3})

A frozenset is an immutable version of a standard Python set. Once you create it using the frozenset() constructor, you can't add or remove elements. This unchangeable nature is its key feature.

  • Because they are immutable, frozenset objects are "hashable." This means you can use them as dictionary keys or as elements inside another set—something you can't do with regular sets. This immutability is similar to creating tuples, which are also immutable collections.
  • You can still perform standard set operations. For example, fs1.intersection(fs2) works as expected, but it returns a new frozenset rather than modifying an existing one.

Set operations with operators

set_a = {1, 2, 3, 4, 5}
set_b = {4, 5, 6, 7, 8}
print("Union:", set_a | set_b)
print("Intersection:", set_a & set_b)
print("Difference (A-B):", set_a - set_b)
print("Symmetric difference:", set_a ^ set_b)--OUTPUT--Union: {1, 2, 3, 4, 5, 6, 7, 8}
Intersection: {4, 5}
Difference (A-B): {1, 2, 3}
Symmetric difference: {1, 2, 3, 6, 7, 8}

Python offers a clean, mathematical syntax for performing set operations. These operators are often more concise and readable than their equivalent method calls, making your code feel more intuitive.

  • The union operator | merges two sets, creating a new one with all unique elements from both.
  • Intersection & finds the common ground, returning only the elements present in both set_a and set_b.
  • Difference - subtracts one set from another, keeping elements from the set on the left that aren't in the one on the right.
  • Symmetric difference ^ gives you elements that are in either set, but not in both.

Move faster with Replit

Replit is an AI-powered development platform that comes with all Python dependencies pre-installed, so you can skip setup and start coding instantly. You can move from learning individual techniques to building complete apps with Agent 4, which takes your idea and handles the code, databases, APIs, and deployment.

Instead of piecing together functions, describe the app you want to build and Agent will take it from idea to working product:

  • A tag management tool that ingests messy lists of keywords and outputs a clean, unique set for your content.
  • An access control utility that compares a user's permissions against a resource's required permissions to grant or deny access.
  • A recommendation engine that finds which products in a new catalog a user has not already purchased.

Simply describe your app, and Replit will write the code, test it, and fix issues automatically, all within your browser.

Common errors and challenges

While sets are powerful, you might run into a few common tripwires that can catch you off guard when you're getting started.

  • Modifying a set during iteration: A classic mistake that triggers a RuntimeError is trying to change a set while you're looping over it. Python protects the set from being altered mid-loop. The standard workaround is to iterate over a copy, like for item in my_set.copy():, which lets you safely modify the original set.
  • Handling unhashable types: You'll hit a TypeError if you try to add an "unhashable" type, such as a list or another regular set. Set elements must be immutable (unchangeable). If you need to store a collection as an element, convert it to a tuple or a frozenset first.
  • Accessing elements by index: Because sets are unordered, they don't support indexing. Trying to access an element with my_set[0] will throw a TypeError since there's no "first" element. If you truly need to access an item by its position, your best bet is to convert the set into a list.

Avoiding RuntimeError when modifying a set during iteration

It’s a common pitfall: you loop through a set to remove certain elements, only to be met with a RuntimeError. Python stops you from changing a set’s size during iteration to prevent unpredictable behavior. The following code demonstrates this exact issue.

numbers = {1, 2, 3, 4, 5}
for num in numbers:
if num % 2 == 0:
numbers.remove(num) # This causes RuntimeError
print(numbers)

The loop fails because it's iterating over the numbers set directly. When numbers.remove(num) changes the set's size, the iterator becomes invalid, triggering the error. The following example demonstrates a safe way to accomplish this.

numbers = {1, 2, 3, 4, 5}
numbers_to_remove = {num for num in numbers if num % 2 == 0}
numbers -= numbers_to_remove
print(numbers)

The safe approach is to first identify the elements you want to remove and collect them in a separate set. The example uses a set comprehension to create numbers_to_remove. Then, it uses the difference update operator (-=) to subtract this new set from the original numbers set. This avoids the RuntimeError because you're not changing the set's size while looping over it. This is a reliable pattern for in-place filtering and demonstrates effective code repair techniques for common iteration errors.

Handling unhashable types in sets with TypeError

Handling unhashable types in sets with TypeError

You'll encounter a TypeError if you try adding a mutable—or changeable—data type to a set. Because set elements must be immutable, they can't be altered after creation. The following code shows what happens when you attempt to add a list.

my_set = {1, 2, 3}
my_set.add([4, 5, 6]) # Lists are unhashable - TypeError
print(my_set)

The add() method fails because lists are mutable and can't be hashed, but sets require all their elements to be immutable. The following example demonstrates the correct way to handle this situation.

my_set = {1, 2, 3}
my_set.update([4, 5, 6]) # update() adds individual elements
print(my_set)

The `TypeError` occurs because add() tries to insert the list as a single, unhashable element. The solution is using update(), which doesn't add the list itself. Instead, it iterates through the provided list and adds each of its items individually to the set. This is the key difference—use add() for a single element and update() to absorb multiple elements from any iterable, preventing the error.

Remembering that sets can't be accessed with index notation

Because sets are unordered, they don't maintain a sequence for their elements. This means you can't access items by their position using index notation. Attempting to do so, as shown in the code below, will result in a TypeError.

fruits = {"apple", "banana", "cherry"}
print(fruits[0]) # TypeError: 'set' object is not subscriptable

The expression fruits[0] fails because it asks for the "first" item, but sets don't have a fixed order, which causes the TypeError. If you need positional access, the following example demonstrates the correct approach.

fruits = {"apple", "banana", "cherry"}
fruits_list = list(fruits)
print(fruits_list[0]) # Convert to list for indexing

The fix is to convert the set into a list using the list() function. This works because lists are ordered collections, so you can access their elements by index. If you need to grab an item from a set by its position, this conversion is your go-to solution. Just remember that since sets are unordered, the position of an element in the resulting list isn't guaranteed to be the same every time.

Real-world applications

Moving beyond the technical details, sets are a powerful tool for solving real-world problems like analyzing text and managing social networks.

Finding unique words in text processing

Sets are incredibly efficient for text analysis, such as quickly identifying all the unique words in a document or a sentence.

text = "to be or not to be that is the question"
words = text.split()
unique_words = set(words)
print("Original text:", text)
print("Unique words:", unique_words)
print(f"Word count: {len(words)}, Unique word count: {len(unique_words)}")

This example shows a classic text processing pattern. The code first uses the split() method to break the sentence into a list of words. Then, it leverages the set() constructor to handle the main task.

  • The conversion from a list to a set is the key step. It automatically filters out all duplicate words, such as "to" and "be". This is one of the most common approaches for removing duplicates from lists.
  • The final output compares the total word count to the unique word count, clearly showing the result of the de-duplication.

Finding common friends with intersection() in social networks

Set operations are a natural fit for social network analysis, allowing you to easily compare friend lists and discover mutual connections with methods like intersection().

user1_friends = {"Alice", "Bob", "Charlie", "David", "Eve"}
user2_friends = {"Bob", "Charlie", "Frank", "Grace", "Heidi"}
common_friends = user1_friends.intersection(user2_friends)
unique_to_user1 = user1_friends - user2_friends
print(f"Common friends: {common_friends}")
print(f"Friends unique to User 1: {unique_to_user1}")
print(f"Total unique friends: {user1_friends | user2_friends}")

This example models two friend lists using sets and then applies powerful operations to analyze their connections. It's a common pattern for comparing any two groups of data.

  • The intersection() method quickly identifies the mutual friends shared by both users.
  • Using the difference operator (-), the code finds friends that are exclusive to user1_friends.
  • Finally, the union operator (|) merges both sets to get a complete list of every unique friend from both accounts.

Get started with Replit

Now, turn your knowledge into a real tool. Describe what you want to build to Replit Agent, like "a tag cleaner that de-duplicates a list of keywords" or "a utility that finds common items between two inventories".

It writes the code, tests for errors, and deploys your application. Start building with Replit.

Build your first app today

Describe what you want to build, and Replit Agent writes the code, handles the infrastructure, and ships it live. Go from idea to real product, all in your browser.

Build your first app today

Describe what you want to build, and Replit Agent writes the code, handles the infrastructure, and ships it live. Go from idea to real product, all in your browser.