One of the better articles I've seen on what "2>&1" does is Bash One-Liners Explained, Part III: All about redirections.
But what the current answers on this question fail to provide is why you'd want to do this after a plain "exec". As the bash man page for the exec command explains: "If command is not specified, any redirections take effect in the current shell".
I wrote a simple script called out-and-err.py that writes a line of output to stdout, and another line to stderr:
#!/usr/bin/python
import sys
sys.stdout.write('this is stdout.\n')
sys.stderr.write('this is stderr.\n')
And then I wrapped that in a shell script called out-and-err.sh with an "exec 2>&1":
#!/bin/bash
exec 2>&1
./out-and-err.py
If I run just the python script, stdout and stderr are separate:
$ ./out-and-err.py 1> out 2> err
$ cat out
this is stdout.
$ cat err
the is stderr.
But if I run the shell script, you can see that the exec takes care of stderr for everything after:
$ ./out-and-err.sh 1> out 2> err
$ cat out
this is stdout.
this is stderr.
$ cat err
$
If your wrapping shell script does a lot more than just the one python command, and you need all output combined into stdout, doing the "exec 2>&1" will make that easy for you.