持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情
介绍
inspect模块为Python内置模块,总体来讲该模块可以提供以下几种服务,当然该模块的作用并不仅限于这几种服务,这里只是列出了较为常用的几种,更多的请参考官方文档。
- 类型检查
- 获取源代码
- 检查类和函数
使用
getmemebers(obj)
该方法可以获取Python中对象的属性名以及属性值,返回的结果是一个列表,列表中的数据是多个元素的元组。该对象可以是Python中的模块、类、函数、内置类...
import inspect
class P:
def __init__(self):
self.name = "inspect"
attribute_list = inspect.getmembers(P)
print(attribute_list)
getmodulename(path)
该方法返回path 路径下模块的名称,该方法会根据文件的扩展名判断是否是合法的Python模块,如果如果路径是 .py 结尾的则返回模块名称(文件名), 否则返回None* 。
import inspect
a = inspect.getmodulename(r"myfile.csv")
print(a) # None
b = inspect.getmodulename(r"m.py")
print(b) # m
类型检查相关方法
在这里只简单的介绍几个简单的类型检查方法,在inspect 模块中,涉及到类型检查的方法非常多,有兴趣的XDM可以参考官方文档(docs.python.org/3.9/library…)中的说明
- ismodule(object) - 判断对象是否是模块,是则返回True,否则返回False
import inspect
import m # 自定义模块,m.py
a = inspect.ismodule(m)
print(a) # True
- isclass(object) - 判断对象是否是类,是则返回True,否则返回False
import inspect
class P:
def __init__(self):
self.name = "inspect"
def test():
"""
:return: int
"""
return 1
a = inspect.isclass(test)
print(a) # False
b = inspect.isclass(P)
print(b) # True
- ismethod(object) - 判断对象是否是绑定方法(包括类绑定和对象绑定),是则返回True,否则返回False
import inspect
class P:
def __init__(self):
self.name = "a"
@classmethod
def test(cls):
return cls().name
def test1(self):
return self.name
@staticmethod
def test2():
return "name"
def test():
"""
:return: int
"""
return 1
a = inspect.ismethod(P.test)
b = inspect.ismethod(P().test1)
c = inspect.ismethod(P.test2)
d = inspect.ismethod(test)
print(a, b, c, d) # True True False False
- isfunction(object) - 判断对象是否是函数,包括lambda 定义的匿名函数,需要注意的是绑定方法会返回False,是则返回True,否则返回False
import inspect
class P:
def __init__(self):
self.name = "a"
@classmethod
def test(cls):
return cls().name
def test1(self):
return self.name
@staticmethod
def test2():
return "name"
def test():
"""
:return: int
"""
return 1
a = inspect.isfunction(P.test)
b = inspect.isfunction(P().test1)
c = inspect.isfunction(P.test2)
d = inspect.isfunction(test)
print(a, b, c, d) # False False True True
检索源代码
- getdoc(object) - 获取对象的文档字符串,如果没有的话就返回None, 如果对象是类的话,本身有文档就返回自己的文档,如果本身没有文档就会去父类中寻找文档,找到就会返回,找不到返回None。
import inspect
import m
class Parent:
"""
doc: parent
"""
def __init__(self):
self.name = "a"
class P(Parent):
def __init__(self):
super().__init__()
@classmethod
def test(cls):
return cls().name
def test1(self):
return self.name
@staticmethod
def test2():
return "name"
def test():
"""
:return: int
"""
return 1
a = inspect.getdoc(P)
b = inspect.getdoc(m)
c = inspect.getdoc(test)
print(a) # doc: parent
print(b) # doc: I am doc
print(c) # :return: int
- getsource(object) - 返回对象的源代码,但是内置的模块、类或者函数会抛出TypeError 错误。
import inspect
import django
def test():
"""
:return: int
"""
return 1
a = inspect.getsource(django)
b = inspect.getsource(test)
c = inspect.getsource(list) # list是Python内置的类
print(a)
print(b)
print(c) # TypeError: <class 'list'> is a built-in class
signature - 检查类和函数
__annotations__- 查看函数或者方法的签名信息,即参数和返回值的详细信息,包括名称和具体数据类型,返回值是字典。
import inspect
from typing import Tuple
class Parent:
"""
doc: parent
"""
def __init__(self):
self.name = "a"
def test(self):
return self.name
def test(a: int, b: int) -> tuple[int, int]:
print(a + b)
return a, b
print(test.__annotations__) # {'a': <class 'int'>, 'b': <class 'int'>, 'return': tuple[int, int]}
print(Parent().test.__annotations__) # {}
我们可以思考一个问题,参数检查势必要在函数执行之前进行,想要在函数执行前增加参数检查的功能势必需要使用装饰器,__annotations__方法返回的值是字典,字典是无序的,而用户按照位置传进来的参数是有序的,如何能够让它们形成对应关系更加方便进行参数检查呢?
此时我们就可以借助inspect 的signature 去获取函数签名,得到的返回值是有序字典。
- signature - 获取函数或者方法的签名信息,将得到的信息存放在有序字典中,从而可以将调用程序是得到的实参与函数签名进行一一对应。同时可以获取每个参数对应的数据类型
import inspect
def test(a: int, b: int) -> tuple[int, int]:
print(a + b)
return a, b
res = inspect.signature(test)
print(res.parameters) # OrderedDict([('a', <Parameter "a: int">), ('b', <Parameter "b: int">)])
print(res.parameters["a"].annotation) # <class 'int'> 通过annotation方法获取参数的数据类型
总结
Python是一门动态解释型语言,因此我们无法在变量赋值时就明确表名数据类型,虽然我们可以使用typing模块来进行类型注解,但是这只是提示作用,并没有进行严格限制,这是动态类型语言的特点,并不能说是缺点,因此在一些特定场景下,需要明确严格参数类型或者需要对模块等进行严格限制的话,可以参考使用inspect模块。