Storing a general python object in a Blender scene
For these cases you can use pickle and base64 to string.
But be aware that you need to use cKDTree according to https://stackoverflow.com/questions/37722991/unable-to-pickle-scipy-spatial-kdtree-objects

import pickle
import base64

# store kdtree
def _set_kdtree_for_object(my_obj, my_kdtree):
    pickled_kdtree = pickle.dumps(my_kdtree)
    # pickled_kdtree is binary convert it to a string
    base64encoded = base64.b64decode(pickled_kdtree).decode('utf-8')
    my_obj['my_list'] = base64encoded

# read back
def _get_kdtree_for_object(my_obj):
    base64encoded = my_obj['my_list']
    pickled_kdtree = base64.b64encode(base64encoded.encode('utf-8'))
    my_kdtree = pickle.loads(pickled_kdtree)
    return my_kdtree


Be aware that exceptions may happen due to different pickle implementations when python is updated in blender.

Depending on the usecase you could also use a global store on object name. This will not store the kdtree in your blend file, but you need to be able to recreate the kdtree when it is not available. This solves issues of python updates.

kdtree_lookup = {}

def _get_or_rebuild_kdtree_for_object(obj):
    global kdtree_lookup
    result = kdtree_lookup.get(obj)
    if result is None:
        # rebuild the kdtree
        ...
        # store it
        kdtree_lookup[obj] = result
    return result


You could also rebuild the kdtree's after loading of the blendfile using an handler.