函数内省(function introspection)

除了__doc__属性, 函数对象还有很多属性,对于下面的函数,可以使用dir()查看函数具有的属性:

def factorial(n):
return 1 if n == 1 else n*factorial(n - 1)
>>> dir(factorial)
['__annotations__', '__call__', '__class__', '__closure__', '__code__',
'__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__',
'__hash__', '__init__', '__kwdefaults__', '__le__', '__lt__', '__module__',
'__name__', '__ne__', '__new__', '__qualname__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']

其中大多数是Python常规类都有的属性,下面重点看看常规对象没有而函数对象有的属性:

>>> class C:pass
...
>>> obj = C()
>>> def func():pass
...
>>> sorted(set(dir(func)) - set(dir(obj))) # 计算差集,然后排序
['__annotations__', '__call__', '__closure__', '__code__', '__defaults__', '__get__', '__globals__', '__kwdefaults__', '__name__', '__qualname__']

对于上面列出的函数特有属性,说明如下:

接下来我们讨论__defaults__, __code__, __annotations__的作用

(一) __defaults__, __code__:

函数对象有个__defaults__属性,他的值是一个元组,里面保存着定位参数和关键字参数的默认值。然而,参数的名称在__code__属性中, 它的值是一个code对象引用,自身也有很多属性

仅限关键字参数的默认值在__kwdefaults__属性中,

我们借用下面的示例说明这些属性的用途:

def clip(text=None, max_length=80):
"""
Return text clipped at the last space before or after max_len
"""
end = None
if len(text) > max_length:
space_before = text.rfind(' ', 0, max_length)
if space_before >= 0:
end = space_before
else:
space_after = text.rfind(' ', max_length)
if space_after >= 0:
end = space_after if end is None:
end = len(text) return text[:end].rstrip()

提取clip函数参数的信息:

>>> from Example5_15 import clip
>>> clip.__defaults__
(None, 80)
>>> clip.__code__
<code object clip at 0x7f8e50658f60, file "/root/python_demo/Example5_15.py", line 1>
>>> clip.__code__.co_varnames
('text', 'max_length', 'end', 'space_before', 'space_after')
>>> clip.__code__.co_argcount
2

从控制台信息可以看出,__code__.co_varnames包含函数参数,并且还包含函数体中的局部变量,函数参数个数由__code__.co_argcount确定(这里不包含前缀为*或者**的变长参数)

从这些属性提取参数信息并不是很方便,我们有更好的方式-------使用inspect模块:

>>> from inspect import signature
>>> sig = signature(clip)
>>> sig
<Signature (text=None, max_length=80)>
>>> for name, param in sig.parameters.items():
... print(param.kind, ':', name, '=', param.default)
...
POSITIONAL_OR_KEYWORD : text = None
POSITIONAL_OR_KEYWORD : max_length = 80

这样就好多了, Inspect.signature 函数返回一个inspect.Signature对象,它有一个parameter属性,这是一个有序映射,把参数名和inspect.Parameter对象对应起来,各个Parameter属性也有自己的属性,比如name, default, kind

如果是非默认值参数,特殊的inspect._empty值表示没有默认值,考虑到上面例子的None是有效默认值,这样处理是合理的

(二) __annotations__属性:

我们把上面的clip函数添加注解,如下所示:

def clip(text: str =None, max_length: 'int > 0'=80) -> str:
"""
:return text clipped at the last space before or after max_len
:param text:
:param max_length:
"""
end = None
if len(text) > max_length:
space_before = text.rfind(' ', 0, max_length)
if space_before >= 0:
end = space_before
else:
space_after = text.rfind(' ', max_length)
if space_after >= 0:
end = space_after if end is None:
end = len(text) return text[:end].rstrip()

注意函数头部的第一行

函数声明中的各个参数可以在:之后添加注解,添加注解的方法:

(1)参数有默认值,注解放在参数名和=号之间

(2)返回值,在)和函数声明尾部的:之间添加->和一个表达式,表达式可以是任何类型

对于注解,Python解释器不做任何处理,只是存储在__annotations__属性(字典形式)中:

>>> from Example5_15 import clip
>>> clip.__annotations__
{'return': <class 'str'>, 'max_length': 'int > 0', 'text': <class 'str'>}

Python 函数内省的更多相关文章

  1. Python函数的内省-Introspection

    Python函数可以进行内省-Introspection,查看函数内部的细节,方式就是使用函数的__code__属性. def func(a, b = 2): return a + b >> ...

  2. python高级(五)—— python函数(一等对象)

    本文主要内容 一等对象 普通函数 & 高阶函数 可调用对象 & 自定义可调用类型 函数内省 函数注释 python高级——目录 文中代码均放在github上:https://githu ...

  3. Python函数装饰器原理与用法详解《摘》

    本文实例讲述了Python函数装饰器原理与用法.分享给大家供大家参考,具体如下: 装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值 ...

  4. Python函数参数和注解是什么

    四种参数 Python函数func定义如下: def func(first, *args, second="Hello World", **kwargs): print(first ...

  5. python 函数之day3

    一 函数的语法及特性 什么是函数? 定义:函数是一个功能通过一组语句的集合,由名字(函数名)将其封装起来的代码块,要想执行这个函数,只要调用其函数名即可. 特性: 减少重复代码 使程序变的可扩展 使程 ...

  6. Python函数作用域的查找顺序

    函数作用域的LEGB顺序 1.什么是LEGB? L:local 函数内部作用域 E:enclosing 函数内部与内嵌函数之间 G:global 全局作用域 B:build-in 内置作用域 2.它们 ...

  7. Python函数讲解

    Python函数

  8. Python函数信息

    Python函数func的信息可以通过func.func_*和func.func_code来获取 一.先看看它们的应用吧: 1.获取原函数名称: 1 >>> def yes():pa ...

  9. Python函数参数默认值的陷阱和原理深究"

    本文将介绍使用mutable对象作为Python函数参数默认值潜在的危害,以及其实现原理和设计目的 本博客已经迁移至: http://cenalulu.github.io/ 本篇博文已经迁移,阅读全文 ...

随机推荐

  1. c#将List转换成DataTable

    前面写了一篇List<T>转换成DataTable,这里主要是完善了前面的代码. 同样使用了emit,我把代码整理后上传了git. 另外增加了特性的设计. 设计了三类特性ColumnTyp ...

  2. C++学习---指针相关

    1.指向 “指针对象” 的 ”指针” 一般指针 int *p1,ival =42; p1 = &ival; 或者 int ival =42,*p1=&val; 代表一个指针对象指向一个 ...

  3. Redis事件

    Redis事件 Redis的ae(Redis用的事件模型库) ae.c Redis服务器是一个事件驱动程序,服务器需要处理以下两类事件: 文件事件(file event):Redis服务器通过套接字与 ...

  4. PHP打包zip并下载

    $file_template = FCPATH.'canddata/cand_picture.zip';//在此之前你的项目目录中必须新建一个空的zip包(必须存在) $downname = $car ...

  5. 今天差点被断电搞死了,幸好IDE的备份救了我

    今天早上,刚好改了几个PAS的源代码,在按CTRL+SHIFT+S(保存全部) 时,突然断电.有电后,发现这些保存的文件都变成乱码了............. DFM,PAS都是这样,幸好DELPHI ...

  6. exynos4412—链接脚本复习

    在u-boot下,定义变量, 编译,编译完后  使用arm-linux-nm arm    没有去头的二进制可执行文件 都在BSS段,均为初始化. 打印之后会出算随机值. 目前还处于uboot阶段,如 ...

  7. Activiti5第一天——待更新

    一.概述 相关介绍资料可以参见:https://www.ibm.com/developerworks/cn/java/j-lo-activiti1/ http://blog.csdn.net/blue ...

  8. 20155204 2016-2017-2 《Java程序设计》第9周学习总结

    20155204 2016-2017-2 <Java程序设计>第9周学习总结 教材学习内容总结 SRP单一职责原则,也叫内聚性,判断srp the 类 方法 itself c与java的区 ...

  9. 20155216 2016-2017-2 《Java程序设计》第三周学习总结

    教材学习内容总结 区分基本类型与类类型 类类型是自己定义产生的,基本类型是long,int,double等类型. 在类的定义过程中,可直接用class XXX {}对每个序定义的值域成员进行定义.这样 ...

  10. 20155321 2016-2017-2 《Java程序设计》第一周学习总结

    学习目标 [√]了解Java基础知识 [√]了解JVM.JRE与JDK,并下载.安装.测试JDK [√]了解PATH.CLASSPATH.SOURCEPATH的作用并会设置 [√]初步使用IDE(推荐 ...