Adding this in another answer, 'cause it is one:
If you want something faster than the "manual" methods given, there's always Numpy:
import numpy
def bxor_numpy(b1, b2):
n_b1 = numpy.fromstring(b1, dtype='uint8')
n_b2 = numpy.fromstring(b2, dtype='uint8')
return (n_b1 ^ n_b2).tostring()
and it's fast:
first_random = urandom(100000)
second_random = urandom(100000)
min(Timer(partial(bxor_inplace, first_random, second_random)).repeat(10, 100))
#>>> 1.5381054869794752
min(Timer(partial(bxor_append, first_random, second_random)).repeat(10, 100))
#>>> 1.5624085619929247
min(Timer(partial(bxor_numpy, first_random, second_random)).repeat(10, 100))
#>>> 0.009930026979418471
So it's 150x faster than the best alternatives posted here.