import inspect


def get_func_args(func, args, kwargs):
    """ 获得函数的所有参数信息，保存在 func_args 中
    输入：
        func: 函数体
        args: 传入的位置参数列表
        kwargs: 传入的命名参数列表
    """
    
    # 获得当前函数的所有参数信息
    full = inspect.getfullargspec(func)  # 含缺省值定义

    # FullArgSpec(args=[], varargs='args', varkw='kwargs', defaults=(),kwonlyargs=[], kwonlydefaults={}, annotations={})
    # print(full)
    # print(args)
    # print(kwargs)
    
    len_fa = len(full.args)  # 定义的位置参数列表
    len_va = len(args)  # 传入的位置参数列表长度
    copy_kwargs = kwargs.copy()  # 用于从传入参数字典中，删除定义的命名参数

    func_args = dict()
    
    # 获得所有位置参数的值：若传入参数有值，则取传入参数，否则取缺省值
    for i, arg in enumerate(full.args):
        if i < len_va:
            func_args[arg] = args[i]
        elif arg in copy_kwargs:
            func_args[arg] = copy_kwargs[arg]
            copy_kwargs.pop(arg)
        else:
            idx = i - len_fa
            if full.defaults is not None and idx < len(full.defaults):
                func_args[arg] = full.defaults[idx]  # 缺省值从后往前定位获取

            else:
                func_args[arg] = None
    
    # 将定义的位置参数之外的传入位置参数，保存到定义的参数名中
    if len_fa < len_va:
        func_args[full.varargs] = args[len_fa:]
    else:
        func_args[full.varargs] = ()
    
    # 对命名参数进行赋值，传入的命令参数字典中有，则取传入字典的值，否则取缺省值
    for item in full.kwonlyargs:
        if item in copy_kwargs:
            func_args[item] = copy_kwargs[item]
            copy_kwargs.pop(item)
        elif full.kwonlydefaults is not None and item in full.kwonlydefaults:
            func_args[item] = full.kwonlydefaults[item]
        else:
            func_args[item] = None
    
    if full.varkw is not None:
        # 将多出的命名参数，保存到指定的参数变量名中
        func_args[full.varkw] = copy_kwargs
    
    # print(func_args)
    return func_args