# 3.4.5. Sets¶

In this section we introduce the Python
type `set`

. As the name suggests,
Python sets are intended to model the standrad
mathematical notion of a set. Like lists, sets are containers
that can contain any kind of object. Like
lists, they are mutable (that is, you can add
things to and remove things from a set);
Unlike lists, sets are unordered, so you don’t add or remove things
by referencing a particular index;
you use the `add`

or `remove`

method,
as shown below.

Just as with other containers, the `in`

operator is a valid test for containment:

```
>>> X = set([1,2,3])
>>> 2 in X
True
>>> 4 in X
False
>>> X[0]
Traceback (most recent call last):
...
TypeError: 'set' object does not support indexing
```

Sets are used when we are trying to keep track of a collection of things, don’t care about order, and especially when we don’t want duplicates. Like mathematical sets, Python sets can be unioned and intersected with other sets:

```
>>> S = set([1,2,3])
>>> T = set([1,2,5])
>>> S.union(T)
set([1, 2, 3, 5])
>>> S.intersection(T)
set([1, 2])
```

These operations build new sets, and do not change `S`

and `T`

:

```
>>> R = S.union(T)
>>> R
set([1, 2, 3, 5])
>>> S
set([1, 2, 3])
>>> T
set([1, 2, 5])
```

There are versions of union
and intersection that do change `S`

and `T`

:

```
>>> S.union_update(T)
>>> S
set([1, 2, 3, 5])
>>> S.intersection_update(T)
>>> S
set([1, 2])
```

Like other Python types, the name of the type can be used as a function to create instances of the type:

```
>>> L = [1,2,3]
>>> S = set(L)
```

Here the `set`

function converts a list into a set. As with
other Python containers, calling the function with no arguments produces
an empty container, in this, the empty set:

```
>>> S = set()
>>> S
set([])
```

Python also provides more compact, and perhaps more familiar notation
for sets as well. So in the following code snippet, the first two
lines create sets and the next two are equivalent to the
`union`

and `intersection`

methods introduced above:

```
>>> S = {1,2,3}
>>> T = {1,2,5}
>>> S | T
set([1, 2, 3, 5])
>>> S & T
set([1, 2])
```

Note that whether curly braces produce a dictionary or
a set depends on what’s **inside** the curly braces:

```
>>> {('a',0),('b',1)}
set([('b', 1), ('a', 0)])
```

Here we have a set of tuples. On the other hand:

```
>>> X = {'a':0 ,'b':1}
>>> type(X)
<type 'dict'>
```

## 3.4.5.1. Immutable sets¶

The immutable version of a list is a tuple. Mutability is the only reason we have a distinction between lists and tuples. But sets are lists with the order taken away. Is there a motivation for a comparable distinction between mutable and immutable sets?

There is, and Python has implemented it. Immutable sets
are called **frozensets**. Frozensets have all the same
operations as sets, except for the ones that change the sets:

```
>>> S = frozenset([1,2,3])
>>> Ss = set([1,2,3])
>>> T = frozenset([4,2,5])
>>> S.union(T)
frozenset([1, 2, 3, 4, 5])
>>> S.update(T)
...
AttributeError: 'frozenset' object has no attribute 'update'
>>> Ss.update(T)
>>> Ss
set([1, 2, 3, 4, 5])
>>> S.issuperset(T)
False
>>> S.pop()
....
AttributeError: 'frozenset' object has no attribute 'pop'
>>> Ss.pop()
1
```

All the set methods with ‘update’ in the name raise
errors for frozensets (`difference_update`

, `union_update`

,
`intersection_update`

, `symmetric_difference_update`

,
and `update`

), and ditto for `pop`

and `remove`

.

See also

Section Mutability (advanced).