inspect是专门用来收集python对象的信息的,可以获取参数信息,原码,解析堆栈,判断对象类型等等。下面看看一些主要用法

import inspect
# 1.判断是不是一个模块
import tornado
print(inspect.ismodule(tornado)) # True
# 2.判断是不是一个类
Foo = type("Foo", (object, ), {})
print(inspect.isclass(Foo)) # True
# 3.判断是不是一个方法。说白了就是判断是不是类里面定义的一个函数,
class A:
def m(self):
...
print(inspect.ismethod(A().m), type(A().m)) # True 
# 4.判断是不是一个方法描述符。说白了就是首先得是一个类的实例对象,并且这个类里面定义了__get__方法,且没有定义__set__方法
class A:
def __get__(self, instance, owner):
...
print(inspect.ismethoddescriptor(A()))
# 5.判断是不是一个数据描述符。说白了就是首先得是一个类的实例对象,并且这个类里面定义了__get__方法和__set__方法
class A:
def __get__(self, instance, owner):...
def __set__(self, instance, value):...
print(inspect.isdatadescriptor(A())) # True
# 6.判断是不是一个函数
print(inspect.isfunction(lambda: ...)) # True
# 7.判断是不是一个生成器函数
def foo(): yield 1
print(inspect.isgeneratorfunction(foo)) # True
# 同时生成器函数也是一个函数
print(inspect.isfunction(foo)) # True
# 8.判断是不是一个协程函数,协程函数必须是由async def语法定义的函数,使用types.coroutine或者asyncio.coroutine装饰的函数都不是
async def foo():
...
print(inspect.iscoroutinefunction(foo)) # True
# 9.判断是不是一个异步生成器函数,异步生成器函数是由async def语法定义,并且函数体内部要包含yield的函数
async def foo():
yield 1
print(inspect.isasyncgenfunction(foo)) # True
# 10.判断是不是一个异步生成器,就是异步生成器函数加上小括号
print(inspect.isasyncgen(foo())) # True
# 11.判断是不是一个生成器, 就是生成器函数加上小括号
def gen(): yield 1
print(inspect.isgenerator(gen())) # True
# 12.判断是不是一个协程,就是协程函数加上小括号
async def foo(): ...
print(inspect.iscoroutine(foo())) # True
# 13.判断是不是一个可以awaitable,说白了就是await一个迭代器对象
async def foo():
await [1, 2, 3].__iter__()
print(inspect.isawaitable(foo())) # True
# 14.判断是不是一个栈帧
def foo():
# 该函数可以获取栈帧
frame = inspect.currentframe()
return frame
print(inspect.isframe(foo())) # True
# 15.判断是是不是code
def foo(): ...
print(inspect.iscode(foo.__code__)) # True
# 16.获取成员
class A:
def __init__(self):...
def parse(self): ...
import pprint
pprint.pprint(inspect.getmembers(A))
‘‘‘
[(‘__class__‘, ),
(‘__delattr__‘, ),
(‘__dict__‘,
mappingproxy({‘__dict__‘: ,
‘__doc__‘: None,
‘__init__‘: ,
‘__module__‘: ‘__main__‘,
‘__weakref__‘: ,
‘parse‘: })),
(‘__dir__‘, ),
(‘__doc__‘, None),
(‘__eq__‘, ),
(‘__format__‘, ),
(‘__ge__‘, ),
(‘__getattribute__‘, ),
(‘__gt__‘, ),
(‘__hash__‘, ),
(‘__init__‘, ),
(‘__init_subclass__‘,
),
(‘__le__‘, ),
(‘__lt__‘, ),
(‘__module__‘, ‘__main__‘),
(‘__ne__‘, ),
(‘__new__‘, ),
(‘__reduce__‘, ),
(‘__reduce_ex__‘, ),
(‘__repr__‘, ),
(‘__setattr__‘, ),
(‘__sizeof__‘, ),
(‘__str__‘, ),
(‘__subclasshook__‘,
),
(‘__weakref__‘, ),
(‘parse‘, )]
‘‘‘
# 17.获取mro,包括自己
class A(object): ...
print(inspect.getmro(A)) # (, )
# 18.获取doc
print(inspect.getdoc(int))
‘‘‘
int([x]) -> integer
int(x, base=10) -> integer
Convert a number or string to an integer, or return 0 if no arguments
are given. If x is a number, return x.__int__(). For floating point
numbers, this truncates towards zero.
If x is not a number or if base is given, then x must be a string,
bytes, or bytearray instance representing an integer literal in the
given base. The literal can be preceded by ‘+‘ or ‘-‘ and be surrounded
by whitespace. The base defaults to 10. Valid bases are 0 and 2-36.
Base 0 means to interpret the base from the string as an integer literal.
>>> int(‘0b100‘, base=0)
4
‘‘‘
# 19.查看对象被定义在哪一个文件里面
from pandas import DataFrame
print(inspect.getfile(DataFrame)) # C:\python37\lib\site-packages\pandas\core\frame.py
# 当然也可以是一个模块
import requests
print(inspect.getfile(requests)) # C:\python37\lib\site-packages\requests\__init__.py
# 20.返回一个给定对象的模块名,不过存在不存在,感觉没卵用
print(inspect.getmodulename(r"C:\python37\lib\site-packages\peeaaawee.py")) # peeaaawee
# 21.和getfile类似
print(inspect.getabsfile(DataFrame)) # c:\python37\lib\site-packages\pandas\core\frame.py
# 22.获取参数信息,但需要传入字节码
def foo(a, b=1): ...
print(inspect.getargs(foo.__code__)) # Arguments(args=[‘a‘, ‘b‘], varargs=None, varkw=None)
print(inspect.getargs(foo.__code__).args) # [‘a‘, ‘b‘]
# 23.获取参数信息吗, 传入函数即可
def foo(a, b=1): ...
print(inspect.getfullargspec(foo)) # FullArgSpec(args=[‘a‘, ‘b‘], varargs=None, varkw=None, defaults=(1,), kwonlyargs=[], kwonlydefaults=None, annotations={})
print(foo.__defaults__) # (1,)
import inspect
def bar():
name = "Mashiro"
age = 16
return foo()
def foo():
name = "Satori"
age = 18
return inspect.currentframe()
# frame叫做栈帧,表示当前函数调用栈的某一帧,是一个上下文。正所谓在python中一切皆对象,这个栈帧也是一个对象。
# 函数执行要在相应的栈帧中执行
# 栈帧有一下几大特性,
# f_back:调用者的上一级栈帧
# f_code:字节码
# f_lineno:栈帧所在的哪一行
# frame是定义在foo函数里面,所以currentframe拿到的是foo的栈帧
# 但是又是通过bar来调用的,所以foo的上一级栈帧就是bar的栈帧
f = bar()
print(f.f_back) # 
print(f.f_code) # 
print(f.f_lineno) # 13
# 这个f_code里面也有很多的属性
# co_name:获取栈帧所对应的函数名
print(f.f_code.co_name) # foo
# co_filename:获取相应的文件名
print(f.f_code.co_filename) # D:/乱七八糟的/龙卷风/3.py
print(f.f_back.f_code.co_name) # bar
print(f.f_back.f_code.co_filename) # D:/乱七八糟的/龙卷风/3.py
# 查看当前的局部变量,可以看到由于栈帧还在,所以局部变量依旧存储在堆上
print(f.f_locals) # {‘name‘: ‘Satori‘, ‘age‘: 18}
# 同理它的上一级栈帧也是
print(f.f_back.f_locals) # {‘name‘: ‘Mashiro‘, ‘age‘: 16}
# 如果是生成器的话,就不需要了
def gen():
yield 1
name = ("xxx", )
yield 2
age = 16
yield 3
gender = "f"
yield 4
return
g = gen()
# 生成器有一个gi_frame属性,可以直接获取
print(g.gi_frame.f_locals) # {}
print(next(g)) # 1
print(g.gi_frame.f_locals) # {}
print(next(g)) # 2
print(g.gi_frame.f_locals) # {‘name‘: ‘xxx‘}
print(next(g)) # 3
print(g.gi_frame.f_locals) # {‘name‘: ‘xxx‘, ‘age‘: 16}
print(next(g)) # 4
print(g.gi_frame.f_locals) # {‘name‘: ‘xxx‘, ‘age‘: 16, ‘gender‘: ‘f‘}
try:
next(g)
except StopIteration as e:
print(e.value) # result