To do fitness sharing, you would have to define your own shared fitness function that depends on the entire population.
Assuming you already defined a fitness function, you could do the following:
from scipy.spatial import distance_matrix
def sharing(distance, sigma, alpha):
res = 0
if distance<sigma:
res += 1 - (distance/sigma)**alpha
return res
def shared_fitness(individual, population, sigma, alpha):
num = fitness(individual)[0]
dists = distance_matrix([individual], population)[0]
tmp = [sharing(d, sigma, alpha) for d in dists]
den = sum(tmp)
return num/den,
This shared fitness will favor individuals with fewer neighbors. sigma is the radius in which neighbors will penalize an individual's shared fitness. If sigma is bigger, then your niches will be further away, and you risk missing a local maximum. If sigma is smaller, you need a larger population, and your algorithm will take longer to run. alpha indicates how strong the penalization for nearby neighbors is.
This shared fitness can then be registered in your toolbox like a regular fitness.
population = toolbox.population()
toolbox.register('evaluate', shared_fitness, population=population, sigma=0.1, alpha=1.)
After that, you can use a standard algorithm like $\mu + \lambda$, that will select offspring based on their fitness, to get niching.