前几篇内容我们详细探讨了如何从Python中获取帮助信息:
前情回顾
1.查看模块、类提供了哪些接口:
需要帮助吗?dir函数的孪生兄弟,Python中魔法方法__dir__详解
2.查看对象内部属性信息:
查看对象内部属性的名称和值,Python“魔法”属性__dict__的使用
3.使用帮助文档的具体操作:
你真的会用帮助文档吗?Get这些神技能,你就是一个Python学霸
上面的内容能够帮助我们很好地理解一个类或者模块,作为初学者,正确使用上面的方法,基本上不存在理解不了的模块(英文不好的小伙伴使用翻译工具)。因为对于知识点的掌握,上面的方法可以很全面地获得模块或者类的信息(第一手资料,来自帮助文档)
inspect来了
总体来讲,上述方法只是入门级别的,而且,封装性不是很好,知识点也很零碎。
今天,给大家介绍一种功能更全的获取现场对象的模块inspect。
inspect模块
该模块功能很强大,它提供了一些函数便于我们了解现场对象,其实就是用来检查活动对象信息的(这个很重要,它可以获取运行时的一些函数信息)。但是我们使用它可以扩展实现一些额外的功能,除了能实现上面的基本功能外,它还有一些很高级的用法:
我们探寻一些更高级的用法
获取模块、类、实例的详细信息;获取模块、类、函数的帮助文档;获得类、方法(函数)的源代码;获取函数的详细参数信息(位置参数、默认参数等)。查看类的层次结构;检查程序执行时的运行时环境。有哪些用处?
它提供的功能很多:
提供一些更加丰富的功能
如果我们没有Pycharm这样强大的编译器(按下Ctrl点击一个类或者函数名即可跳转到源代码中),我们使用inspect提供的接口,同样可以实现查看类或函数源代码的功能;
可以查看源代码
我们在调试程序时,是不是觉得类似Pycharm、Spyder、WingIDE等这类编译器很强大?能够实时显示某一函数的运行时状态信息,我们使用inspect模块也可以获取到这些信息;
调试程序
对于多继承类,如何判断子类首先继承哪个父类,使用inspect模块提供的接口很容易找到这个父类,并且它还能够清楚展示类继承的层次体系,这比单纯使用dir(cls)获取到的类的继承信息更加清楚;
研究类的层次结构
怎么样,通过上面的解释是不是瞬间感觉它的功能丰富了?
今天,我们先来了解下它是如何获取模块、类、实例的详细信息的
示例模块
首先,我们创建一个模块,用于测试
demo模块
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:bob
# ProjectName : bowen
# DefaultFileName : demo.py
# User : Administrator
# Time : 2020/1/7 22:45
# IDEName : PyCharm
"""这是一个示例模块,用于测试inspect模块
"""
def module_level_function(arg1, arg2='default', *args, **kwargs):
"""这个函数是在模块中定义的函数."""
local_variable = arg1 * 2
return local_variable
class A(object):
"""模块中的自定义类A"""
def __init__(self, name):
self.name = name
def get_name(self):
"返回类的实例的名称"
return self.name
instance_of_a = A('一个实例')
class B(A):
"""这是类B
它继承自A类.
"""
# 这个方法是B类独有的方法.
def do_something(self):
"""B类的实例提供的接口"""
def get_name(self):
"重写了A类的方法"
return 'B(' + self.name + ')'
大家可以复制粘贴到自己的电脑中,保存为demo.py
getmembers()了解内容
使用getmembers()发现成员对象的属性,返回结果取决于想要了解的对象类型,模块返回其中包含的类和函数,类则返回其包含的方法和属性。
函数使用方法
inspect.getmembers(modelName or clsName or InstanceName or funcName, inspect.ismodel or inspect.isclass or inspect.ismethod or inspect.isfunction or etc.)
函数中第一个参数传入模块、类、实例或函数的名称,第二个参数用来过滤返回的对象(如ismodel过滤模块、isclass过滤类)
函数返回值是一个元组列表,元组中包含两个值(成员名和成员类型)
模块信息
import demo
import inspect
for name, data in inspect.getmembers(demo):
if name.startswith('__'):
continue
print('{} : {}'.format(name, data))
运行结果如下
输出模块中的类和函数(包含内存地址)
只检查其中的类呢?可以将第二个参数设置为inspect.isclass即可。
for name, data in inspect.getmembers(demo, inspect.isclass):
if name.startswith('__'):
continue
print('{} : {}'.format(name, data))
>>>
A :
B :
类信息
类信息获取
显示类的所有信息,代码如下:
import demo
import inspect
import pprint
pprint.pprint(inspect.getmembers(demo.A), width=70)
返回了该类的所有信息,包括属性、方法、槽以及类的其它成员,多个元组组成的列表。
[('__class__', ),
('__delattr__',
),
('__dict__',
mappingproxy({'__dict__': ,
'__doc__': '模块中的自定义类A',
'__init__': ,
'__module__': 'demo',
'__weakref__': ,
'get_name': })),
('__dir__', ),
('__doc__', '模块中的自定义类A'),
('__eq__', ),
('__format__', ),
('__ge__', ),
('__getattribute__',
),
('__gt__', ),
('__hash__', ),
('__init__', ),
('__init_subclass__',
),
('__le__', ),
('__lt__', ),
('__module__', 'demo'),
('__ne__', ),
('__new__',
),
('__reduce__', ),
('__reduce_ex__', ),
('__repr__', ),
('__setattr__',
),
('__sizeof__', ),
('__str__', ),
('__subclasshook__',
),
('__weakref__', ),
('get_name', )]
inspect.ismethod和inspect.isfunction的区别
inspect.ismethod只识别类的实例的绑定方法,inspect.isfunction识别类的所有方法。
pprint.pprint(inspect.getmembers(demo.instance_of_a, inspect.ismethod), width=70)
>>>
[('__init__',
>),
('get_name',
>)]
pprint.pprint(inspect.getmembers(demo.B, inspect.ismethod), width=70)
>>>
[('__init__', ),
('do_something', ),
('get_name', )]
从A类继承的方法会被标识为B类的方法
获取帮助文档
获取帮助文档
使用inspect.getdoc()可以获取对象的docstring,返回值是对象的__doc__属性值,tab被扩展为空格,并且缩进保持一致。看下使用getdoc()和__doc__的区别:
print('B.__doc__')
print(demo.B.__doc__)
print('\ngetdoc(B)')
print(inspect.getdoc(demo.B))
两者处理方式稍有差异,如图
处理差异
当然,除了docstring,还可以从实现对象的源文件中获取注释,getcomments()会查看对象的源文件,并查找实现代码前的注释。如:
print(inspect.getcomments(demo.B.do_something))
>>>
# 这个方法是B类独有的方法.
函数中传入模块名称,则返回该模块的第一个注释(出现空行表示注释结束)
print(inspect.getcomments(demo.B.do_something))
>>>
# -*- coding:utf-8 -*-
# Author:bob
# ProjectName : bowen
# DefaultFileName : demo.py
# User : Administrator
# Time : 2020/1/7 22:45
# IDEName : PyCharm
我的返回了一串自定义的编译信息。
好了,今天的内容就到这里了,今天只是些基本操作,对于重要内容我们留到后面,后续为大家奉上如何使用inspect模块进行一些更高级的操作。
转载请注明出处,百家号:Python高手养成