**Sets are used to store an unordered, unindexed collection of values in a single variable. **Sets are mutable and have a highly efficient method to check whether an item is present in the set or not. Sets use the hash table data structure to achieve such efficiency.

Set items cannot be accessed like lists, because they are unindexed. These are one of the four built-in data structures in Python.

`s = {5, "a", 7.8, [1, "j"], ("p", 3), "c"}`

**Unordered**- Set items are unordered. They are not stored in any particular order. They cannot be accessed using indexes or keys.**Unchangeable**- Set items cannot be changed after the set is created. New items can be added to a set, but pre-existing items cannot be changed.**Duplicacy not allowed**- A set cannot have duplicate values. Each item exists only once in a set.**Iterable**- Sets are iterable data structures.- The
**len() function**can be used to calculate the length of a set. - Sets can contain items of
**different data types**. **Sets are implemented by using hash tables**which are based on linked lists that are used to store multiple items in a single index position

Sets can be created in two ways.

- By simply enclosing the set values in a pair of
**curly {} brackets**.

```
s = {"a", 1, 2.6}
print(s)
```

output

`{"a", 1, 2.6}`

- By using the
**set() constructor**.

```
s = set((1, 2, "v", 96))
print(s)
```

output

`{1, 2, "v", 96}`

Set items cannot be accessed using indexes or keys.

Iterator keywords like 'for' and 'in' can be used to iterate sets and access it's members.

```
s = {1, 2, "v", 96}
for x in s:
print(x)
```

output

```
1
2
"v"
96
```

Elements can be added to a set in several ways.

The **add() function** can be used.

Syntax:

`<set name>.add( <item to be added> )`

An example of the above function is,

```
s = {1, "a", 3.5}
s.add("b")
print(s)
```

output

`{1, "a", 3.5, "b"}`

The **update() function** can be used to add single items as well as values present in an iterable to a set.

Syntax:

`<set variable>.update( <item(s) to be added> )`

for example,

```
s.update("c")
s.update([8, 9])
print(s)
```

output

`{1, "a", 3.5, "b", 8, 9}`

There are several methods to delete items from a set.

The **remove() function** removes the value given as the argument from the specified set. It raises an error in case the value does not exist in the set.

```
s = {1, "a", 3.5}
s.remove("a")
print(s)
```

output

`{1, 3.5}`

The **discard() function** does the same thing as the remove() function. The only difference lies in the fact that the discard() function does not raise an error in case the specified value to be removed is absent in the set.

```
s = {1, "a", 3.5}
s.discard("a")
print(s)
```

output

`{1, 3.5}`

The **pop() function** can also be used to delete items in a list. It deletes the last added item to the list. Since lists are unordered, one will not know which item is removed.

The pop() function returns the popped value.

```
s = {1, "a", 3.5}
print(s.pop())
```

output

`3.5`

The **clear() function** clears a set.

```
s = {1, "a", 3.5}
s.clear()
print(s)
```

output

`{}`

The** 'del' keyword** deletes the entire set from existence.

```
s = {1, "a", 3.5}
del s
print(s)
```

output

```
Traceback (most recent call last):
File "del.py", line 3, in <module>
print(s)
NameError: name 's' is not defined
```

The **union()** function or the '|' symbol merges two sets and keeps values from both sets without repetition.

Syntax:

`<new set variable> = <set 1>.union( <set 2> )`

for example,

```
s1 = {"a", "b"}
s2 = {1, 2, 3}
print(s1.union(s2))
```

output

`{"a", "b", 1, 2, 3}`

The** intersection()** function or the '&' operator merges two sets and keeps only the values present in both sets.

Syntax:

`<set 1>.intersection( <set 2> )`

for example,

```
s1 = {"a", "b", 2}
s2 = {1, 2, 3, "b"}
print(s1.intersection(s2))
```

output

`{2, "b"}`

The **intersection_update()** function updates the first set with the merged set.

The **symmetric_difference()** function or the '^' operator returns a new list that contains elements that are present in either list, but not in both.

Syntax:

`<new variable> = <set 1>.symmetric_difference( <set 2> )`

for example,

```
s1 = {"a", "b", 2}
s2 = {1, 2, 3, "b"}
print(s1.symmetric_difference(s2))
```

output,

`{"a", 1, 3}`

The** symmetric_difference_update()** function updates the first set with the merged set.

Say s1 and s2 are two sets.

Operator |
Description |

s1 == s2 | Set equivalence |

s1 != s2 | Set non-equivalence |

s1 <= s2 | s1 is a subset of s2 |

s1 < s2 | s1 is a proper subset of s2 |

s1 >= s2 | s1 is a superset of s2 |

s1 > s2 | s1 is a proper superset of s2 |

s1 | s2 | Set union |

s1 & s2 | Set intersection |

s1 ^ s2 | Set symmetric difference |

s1 - s2 | Set difference (elements present in s1 but not in s2) |

The following methods are built-in methods to manipulate sets in Python.

Method |
Description |

add() | Adds an element to the set |

clear() | Removes all elements from the set |

copy() | Returns a copy of the set |

difference() | Returns a new set with the set difference |

difference_update() | Updates the first set with a resultant difference set |

discard() | Removes specified item |

isdisjoint() | Returns whether the intersection is present between two sets or not |

issubset() | Returns whether one set is a subset of the other or not |

issuperset() | Returns whether a set is the superset of the other or not |

pop() | Removes an element from the set |

remove() | Removes the specified element from the set |

symmetric_difference() | Returns a new set with the symmetric difference between two sets |

symmetric_difference_update() | Updates the first set with the symmetric difference of the two sets |

union() | Returns a new set with the union of two sets |

update() | Updates the first set with the union of the two sets |

**Frozen sets** are similar to sets. The only difference is frozen sets are immutable. That is, once created, elements cannot be added nor removed from frozen sets. It freezes the iterable that is passed through the constructor and makes them unchangeable.

The **frozenset()** constructor function can be used to create frozen sets in Python.

```
s = {1, 2, 5, 9}
f = frozenset(s)
print(f)
```

output

`{1, 2, 5, 9}`

The frozen set constructor can take any iterable as its argument.

In case one tries to add a value to a frozen set, an error occurs.

```
f = frozenset({1, 2, 3})
f.add(5)
```

output

```
Traceback (most recent call last):
File "sets.py", line 10, in <module>
f.add(5)
AttributeError: 'frozenset' object has no attribute 'add'
```