<p>I understand that these methods are for pickling/unpickling and have no relation to the reduce built-in function, but what's the difference between the 2 and why do we need both?</p>

The docs
say that
If provided, at pickling time
```
__reduce__()
```
will be called with no
arguments, and it must return either a
string or a tuple.
On the other hand,
It is sometimes useful to know the
protocol version when implementing
```
__reduce__
```
. This can be done by
implementing a method named
```
__reduce_ex__
```
instead of
```
__reduce__
```
.
```
__reduce_ex__
```
, when it
exists, is called in preference over
```
__reduce__
```
(you may still provide
```
__reduce__
```
for backwards
compatibility). The
```
__reduce_ex__
```
method will be called with a single
integer argument, the protocol
version.
On the gripping hand,
Guido says
that this is an area that could be cleaned up.