Simple spatial grid for particle system
You could rewrite your key() method and use it to much greater effect, reducing repeated code.

def key(self, co, radius=0):
    return tuple((c + radius) // self.cell_size for c in co)


You can then call key() in both add_item() and check_sphere(). In add_item() it will replace k, while in check_sphere() you can use it to define your ranges.

After that I would look for a way to flatten those nested for loops which will likely be an algorithm change. Hopefully someone else has some ideas there.