'Chooses k unique random elements from a population sequence.
Returns a new list containing elements from the population while
leaving the original population unchanged.  The resulting list is
in selection order so that all sub-slices will also be valid random
samples.  This allows raffle winners (the sample) to be partitioned
into grand prize and second place winners (the subslices).
Members of the population need not be hashable or unique.  If the
population contains repeats, then each occurrence is a possible
selection in the sample.
To choose a sample in a range of integers, use xrange as an argument.
This is especially fast and space efficient for sampling from a
large population:   sample(xrange(10000000), 60)'

def sample(self, population, k):

    n = len(population)
    if (not (0 <= k <= n)):
        raise ValueError('sample    larger    than    population')
    random = self.random
    _int = int
    result = ([None] * k)
    setsize = 21
    if (k > 5):
        setsize += (4 ** _ceil(_log((k * 3), 4)))
    if ((n <= setsize) or hasattr(population, 'keys')):
        pool = list(population)
        for i in xrange(k):
            j = _int((random() * (n - i)))
            result[i] = pool[j]
            pool[j] = pool[((n - i) - 1)]
    else:
        try:
            selected = set()
            selected_add = selected.add
            for i in xrange(k):
                j = _int((random() * n))
                while (j in selected):
                    j = _int((random() * n))
                selected_add(j)
                result[i] = population[j]
        except (TypeError, KeyError):
            if isinstance(population, list):
                raise
            return self.sample(tuple(population), k)
    return result
