howeveri strongly recommend not making such optimizations until you have proven that the readable version is too slow now that we have some plumbing in placelet' do the actual -nearest neighbor implementation this seems like good place to use coroutine here it is with some test code to ensure it' yielding sensible valuesdef nearest_neighbors(model_colorsnum_neighbors)model list(model_colorstarget yield while truedistances sorted((color_distance( [ ]target)cfor in model)target yield [ for in distances[ :num_neighborsmodel_colors load_colors(dataset_filenametarget_colors generate_colors( get_neighbors nearest_neighbors(model_colors next(get_neighborsfor color in target_colorsdistances get_neighbors send(colorprint(colorfor in distancesprint(color_distance(colord[ ]) [ ]the coroutine accepts two argumentsthe list of colors to be used as modeland the number of neighbors to query it converts the model to list because it' going to be iterated over multiple times in the body of the coroutineit accepts tuple of rgb color values using the yield syntax then it combines call to sorted with an odd generator expression see if you can figure out what that generator expression is doing it returns tuple of (distancecolor_datafor each color in the model rememberthe model itself contains tuples of (colorname)where color is tuple of three rgb values thereforethe generator is returning an iterator over weird data structure that looks like this(distance(rgb)color_name