函数内省(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. html网站meta标签大全

    案例 一.天猫 <meta charset="utf-8"> <title>天猫TMALL</title> <meta name=&quo ...

  2. jquery选择器基础

    简单选择器 类 id 元素/标签 * 复合(sel1,sel2)逗号隔开 层次选择器 s1 s2:后代选择器,空格隔开 p>c:子代选择器:不包括孙代及以下 p+next :相邻选择器 p~su ...

  3. js时间与毫秒互相转换

    1)日期转换为毫秒 如果格式是:yyyy/mm/dd hh:mm:ss可以直接转换.var oldTime = (new Date("2018/07/09 14:13:11")). ...

  4. 初识spark

    一. spark 概述 1.是什么: ​ Apache Spark 是专为大规模数据处理而设计的快速通用的计算引擎.2012年,它是由加州伯克利大学AMP实 验室开源的类 Hadoop MapRedu ...

  5. DP_最长公共子序列/动规入门

    学自:https://open.163.com/movie/2010/12/L/4/M6UTT5U0I_M6V2U1HL4.html 最长公共子序列:(本文先谈如何求出最长公共子序列的长度,求出最长公 ...

  6. 推荐一个学习Flex chart的好网站

    推荐一个学习Flex chart的好网站 2013-03-04 14:16:56|  分类: Flex |  标签: |字号大中小 订阅     推荐一个学习Flex chart的好网站 最近在做一个 ...

  7. 20155217 实验二 Java面向对象程序设计 实验报告

    20155217 实验二 Java面向对象程序设计 实验报告 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模 ...

  8. 20155236 《Java程序设计》实验三(敏捷开发与XP实践)实验报告

    20155236 <Java程序设计>实验三(敏捷开发与XP实践)实验报告 一.实验内容及步骤 XP基础 XP核心实践 相关工具 实验内容 1.在IDEA中使用工具(Code->Re ...

  9. su的使用与退出

    偶尔用回到ubuntu系统,想切换到su,总是显示不成功,也许是初次使用,即需要设定一下: 使用sudo $:sudo passwd 系统提示输入密码,即安装时的用户密码,然后,系统提示输入两次新密码 ...

  10. 【SQLSERVER】递归查询算法实例

    一.递归查询 1.结构: 递归CTE最少包含两个查询(也被称为成员). 第一个查询为定点成员,定点成员只是一个返回有效表的查询,用于递归的基础或定位点. 第二个查询被称为递归成员,使该查询称为递归成员 ...