Python: inspect


 

 

import inspect


def b(x, y: int = 5, *args, z, t=55, **kwargs) -> int:
    return x + y


signature = inspect.signature(b)

print(signature)
print(signature.parameters)

for i, (name, parameter) in enumerate(signature.parameters.items()):
    # name, parameter = item
    print(i + 1, name, parameter.annotation, parameter.kind, parameter.default)

    print(parameter.default is parameter.empty, end='\n' * 2)

print(x=5) 错在 x=5 是关键字传参, print函数没有定义x参数

import inspect, functools


def discretion(fn):
    @functools.wraps(fn)
    def wrapper(*args, **kwargs):
        signature = inspect.signature(fn)
        parameters = signature.parameters  # OrderedDict
        print(parameters)
        # OrderedDict([('x', < Parameter "x" >), ('y', < Parameter "y: int = 5" >), ('args', < Parameter "*args" >), ('z', < Parameter "z" >), ('t', < Parameter "t=55" >), ('kwargs', < Parameter "**kwargs" >)])
        # for parameter in parameters.values():
        #     print(parameter.name,parameter.annotation,parameter.kind,parameter.default)

        # 找到没有显式传递的默认值参数 ******* args, kwargs 不可能有默认值
        # def b(x, y: int = 5, *args, z=55, t, **kwargs): pass
        # 传递的默认值参数: 1. position 2. keyword only

        keys = tuple(parameters.keys())
        default_parameters = list(keys)  # 所有默认形参

        print(f'keys: {keys}')
        print(f'args: {args}')
        print(f'kwargs: {kwargs}')

        # position arguments
        for i, v in enumerate(args):
            name = keys[i]
            default_parameters.remove(name)

            if parameters[name].annotation is inspect._empty:
                continue  # 类型为空, 跳过检查
            if isinstance(v, parameters[name].annotation):
                print(f'name: {name}, value: {repr(v)}, type: {parameters[name].annotation}')
            else:
                raise TypeError(f'value {repr(v)} is not type {parameters[name].annotation}')

        # keyword arguments
        for k, v in kwargs.items():  # Refactor -> Extract Method 提取公共方法
            default_parameters.remove(k)

            if parameters[k].annotation is parameters[k].empty:
                continue
            if isinstance(v, parameters[k].annotation):
                print(f'name: {k}, value: {repr(v)}, type: {parameters[k].annotation}')
            else:
                raise TypeError(f'value {repr(v)} is not type {parameters[k].annotation}')

        # filter parameter using default
        if 'args' in default_parameters:
            default_parameters.remove('args')
        if 'kwargs' in default_parameters:
            default_parameters.remove('kwargs')

        for parameter in default_parameters:
            print(f'parameter {parameter} using default value {parameters[parameter].default}')

        ret = fn(*args, **kwargs)
        return ret

    return wrapper


@discretion
def b(x: int, y: str = '5') -> None:
    print(x, y)


# b('5', 5)
# b(4)  # y有默认值, discretion没做检查
# b(4, '5')

@discretion
def p(x, y: int = 5, *args, z=55, t, **kwargs):
    print(f'x: {x}, y: {y}, args: {args}, z: {z}, t: {t}, kwargs: {kwargs}')


# p(555, 22, 33, t=666)  # x: 555, y: 22, args: (33,), z: 55, t: 666, kwargs: {}

p(555, t=666)
# keys: ('x', 'y', 'args', 'z', 't', 'kwargs')
# args: (555,)
# kwargs: {'t': 666}