美文网首页
获取关于参数的信息

获取关于参数的信息

作者: SHISHENGJIA | 来源:发表于2017-05-17 13:32 被阅读21次

    先来看个关于HTTP微框架Bobo的例子

    import bobo
    
    @bobo.query('/')
    def hello(person):
        return 'Hello %s!' % person
    

    bobo.query 装饰器把一个普通的函数(如 hello)与框架的请求处理机制集成起来了。Bobo 会内省 hello 函数,发现它需要一个名为 person 的参数,然后从请求中获取那个名称对应的参数,将其传给 hello 函数
    重点是,Bobo 是怎么知道函数需要哪个参数的呢?它又是怎么知道参数有没有默认值呢?
    其实函数对象有个 defaults 属性,它的值是一个元组,里面保存着定位参数和关键字参数的默认值。仅限关键字参数的默认值在 kwdefaults 属性中。然而,参数的名称在 code 属性中,它的值是一个 code 对象引用,自身也有很多属性。
    下面看一下提取关于函数参数的信息的示例

    def tag(name, age=12, *content, cls=None, **attrs):
        x = 2
        pass
    
    print(tag.__defaults__)
    print(tag.__kwdefaults__)
    print(tag.__code__.co_varnames)
    print(tag.__code__.co_argcount)
    
    """
    (12,)
    {'cls': None}
    ('name', 'age', 'cls', 'content', 'attrs', 'x')
    2
    """
    

    参数名称在 __code__.co_varnames 中,不过里面还有函数定义体中创建的局部变量。
    参数名称是前 N 个字符串,N 的值由 __code__.co_argcount 确定, 但是不包含前缀为 *** 的变长参数。
    参数的默认值只能通过它们在 __defaults__ 元组中的位置确定,因此要从后向前扫描才能把参数和默认值对应起来。在这个示例中函数有两个参数(除了变长参数和仅限关键字参数),nameage,其中一个有默认值,即 12,因此它必然属于最后一个参数,即 age。
    上面的实例看起来有些别扭,当然有更好的方式可以查看函数参数的信息,使用 inspect 模块

    from inspect import signature
    
    sig = signature(tag)
    
    print(str(sig))
    
    for name, param in sig.parameters.items():
        print(param.kind, ':', name, '=', param.default)
    
    """
    (name, age=12, *content, cls=None, **attrs)
    POSITIONAL_OR_KEYWORD : name = <class 'inspect._empty'>
    POSITIONAL_OR_KEYWORD : age = 12
    VAR_POSITIONAL : content = <class 'inspect._empty'>
    KEYWORD_ONLY : cls = None
    VAR_KEYWORD : attrs = <class 'inspect._empty'>
    """
    

    inspect.signature 函数返回一个 inspect.Signature 对象,它有一个 parameters 属性,这是一个有序映射,把参数名和 inspect.Parameter 对象对应起来。各个 Parameter 属性也有自己的属性,例如 namedefaultkind。特殊的 inspect._empty 值表示没有默认值,考虑到 None 是有效的默认值(也经常这么做),而且这么做是合理的。

    另外,inspect.Signature 对象有个 bind 方法,它可以把任意个参数绑定到签名中的形参上,所用的规则与实参到形参的匹配方式一样。框架可以使用这个方法在真正调用函数前验证参数。

    sig = signature(tag)
    my_tag = {'name': 'img', 'title': 'Cookbook', 'cls': 'framed'}
    
    bound_args = sig.bind(**my_tag)
    for name, value in bound_args.arguments.items():
        print(name, '=', value)
     
    """
    name = img
    cls = framed
    attrs = {'title': 'Cookbook'}
    """
    

    如果把必须指定的参数 namemy_tag 中删除,那么调用 sig.bind(**my_tag) 将会抛出 TypeError , 抱怨缺少 name 参数。

    相关文章

      网友评论

          本文标题:获取关于参数的信息

          本文链接:https://www.haomeiwen.com/subject/tovrxxtx.html