<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def get_kernel_string(kernel_source, params=None):
 """ retrieve the kernel source and return as a string This function processes the passed kernel_source argument, which could be a function, a string with a filename, or just a string with code already. If kernel_source is a function, the function is called with instance parameters in 'params' as the only argument. If kernel_source looks like filename, the file is read in, but if the file does not exist, it is assumed that the string is not a filename after all. :param kernel_source: One of the sources for the kernel, could be a function that generates the kernel code, a string containing a filename that points to the kernel source, or just a string that contains the code. :type kernel_source: string or callable :param params: Dictionary containing the tunable parameters for this specific kernel instance, only needed when kernel_source is a generator. :type param: dict :returns: A string containing the kernel code. :rtype: string """

    #logging.debug('get_kernel_string called with %s', str(kernel_source))
    logging.debug('get_kernel_string called')

    kernel_string = None
    if callable(kernel_source):
        kernel_string = kernel_source(params)
    elif isinstance(kernel_source, str):
        if looks_like_a_filename(kernel_source):
            kernel_string = read_file(kernel_source) or kernel_source
        else:
            kernel_string = kernel_source
    else:
        raise TypeError("Error kernel_source is not a string nor a callable function")
    return kernel_string