从方法对象获取方法调用及其参数
Getting method calls and their arguments from method object
使用 pythons inspect
模块我已经隔离了一个方法对象,我现在需要单步执行方法中的源代码以找到对某些其他方法的调用并获取它们的参数。
例如,假设在下面 class:
def my_method():
print('hello')
foobar('apple', 'pear', 6)
print('world')
foobar(1, 2, 3)
return foobar('a', 'b')
我需要提取传递给 foobar()
的参数列表:
[('apple', 'pear', 6), (1, 2, 3), ('a', 'b', None)]
可以假定所有参数都是硬编码的而不是动态的。
给定一个来自 inspect
包的方法对象,我如何检查所述方法中的方法调用?
尝试次数
- 我试过将正则表达式与
inspect.getsourcelines(method)
一起使用,但如果参数语法发生变化,这会中断。
- 我已经用 pythons
ast
模块研究了抽象语法树,但还没有找到任何解决方案。
- 必须有一种方法可以使用
inspect
完成此操作,但我还是没有找到任何解决方案。
这并不完美,但应该是一个开始,稍后我会添加一个更好的实现:
from ast import parse, Call, walk
import importlib
import inspect
mod = "test"
mod = importlib.import_module(mod)
p = parse(inspect.getsource(mod))
from ast import literal_eval
vals = []
for node in p.body:
if isinstance(node, FunctionDef) and node.name == "my_method":
for node in walk(node):
if isinstance(node,Call) and node.func.id == "foobar":
vals.append([literal_eval(val) for val in node.args])
print(vals)
[['apple', 'pear', 6], [1, 2, 3], ['a', 'b']]
test.py 看起来像:
def foobar(a=0, b=0, c=None):
return a, b, c
def other_method(x,y,z):
return x,y,z
def my_method():
print('hello')
foobar('apple', 'pear', 6)
print('world')
foobar(1, 2, 3)
for i in range(10):
if i > 9:
s = foobar(4, 5, 6)
print(s)
return foobar('a', 'b')
def my_method2():
foobar('orange', 'tomatoe', 6)
foobar(10, 20, 30)
for i in range(10):
if i > 9:
foobar(40, 50, 60)
other_method("foo","bar","foobar")
return foobar('c', 'd')
如果您混合使用两者,则需要以某种方式将 print('world')
之后的调用更改为 foobar(a=1, b=2, c=3)
vals = []
for node in p.body:
if isinstance(node, FunctionDef) and node.name == "my_method":
for node in walk(node):
if isinstance(node, Call) and node.func.id == "foobar":
kws = node.keywords
if kws:
print("Found keywords",[(kw.arg, literal_eval(kw.value)) for kw in kws])
else:
print([literal_eval(val) for val in node.args])
输出:
[['apple', 'pear', 6], [], ['a', 'b'], [4, 5, 6]]
['apple', 'pear', 6]
('Found keywords', [('a', 1), ('b', 2), ('c', 3)])
['a', 'b']
[4, 5, 6]
使用 ast.Nodevisitor 查找所有 Call 对象将 return 在所有函数中对 "foobar" 的所有调用:
from ast import parse, NodeVisitor, literal_eval
import importlib
import inspect
mod = "test"
mod = importlib.import_module(mod)
p = parse(inspect.getsource(mod))
class FindCall(NodeVisitor):
def __init__(self, *args):
if len(args) < 1:
raise ValueError("Must supply at least ine target function")
self.result = {arg: []for arg in args}
def visit_Call(self, node):
if node.func.id in self.result:
self.result[node.func.id].append(map(literal_eval, node.args))
# visit the children
self.generic_visit(node)
fc = FindCall("foobar")
fc.visit(p)
print(fc.result)
输出:
from pprint import pprint as pp
pp(fc.result)
{'foobar': [['apple', 'pear', 6],
[1, 2, 3],
[4, 5, 6],
['a', 'b'],
['orange', 'tomatoe', 6],
[10, 20, 30],
[40, 50, 60],
['c', 'd']],
'other_method': [['foo', 'bar', 'foobar']]}
您可以再次添加对 kwargs 的搜索,并且只搜索特定的函数。
使用 pythons inspect
模块我已经隔离了一个方法对象,我现在需要单步执行方法中的源代码以找到对某些其他方法的调用并获取它们的参数。
例如,假设在下面 class:
def my_method():
print('hello')
foobar('apple', 'pear', 6)
print('world')
foobar(1, 2, 3)
return foobar('a', 'b')
我需要提取传递给 foobar()
的参数列表:
[('apple', 'pear', 6), (1, 2, 3), ('a', 'b', None)]
可以假定所有参数都是硬编码的而不是动态的。
给定一个来自 inspect
包的方法对象,我如何检查所述方法中的方法调用?
尝试次数
- 我试过将正则表达式与
inspect.getsourcelines(method)
一起使用,但如果参数语法发生变化,这会中断。 - 我已经用 pythons
ast
模块研究了抽象语法树,但还没有找到任何解决方案。 - 必须有一种方法可以使用
inspect
完成此操作,但我还是没有找到任何解决方案。
这并不完美,但应该是一个开始,稍后我会添加一个更好的实现:
from ast import parse, Call, walk
import importlib
import inspect
mod = "test"
mod = importlib.import_module(mod)
p = parse(inspect.getsource(mod))
from ast import literal_eval
vals = []
for node in p.body:
if isinstance(node, FunctionDef) and node.name == "my_method":
for node in walk(node):
if isinstance(node,Call) and node.func.id == "foobar":
vals.append([literal_eval(val) for val in node.args])
print(vals)
[['apple', 'pear', 6], [1, 2, 3], ['a', 'b']]
test.py 看起来像:
def foobar(a=0, b=0, c=None):
return a, b, c
def other_method(x,y,z):
return x,y,z
def my_method():
print('hello')
foobar('apple', 'pear', 6)
print('world')
foobar(1, 2, 3)
for i in range(10):
if i > 9:
s = foobar(4, 5, 6)
print(s)
return foobar('a', 'b')
def my_method2():
foobar('orange', 'tomatoe', 6)
foobar(10, 20, 30)
for i in range(10):
if i > 9:
foobar(40, 50, 60)
other_method("foo","bar","foobar")
return foobar('c', 'd')
如果您混合使用两者,则需要以某种方式将 print('world')
之后的调用更改为 foobar(a=1, b=2, c=3)
vals = []
for node in p.body:
if isinstance(node, FunctionDef) and node.name == "my_method":
for node in walk(node):
if isinstance(node, Call) and node.func.id == "foobar":
kws = node.keywords
if kws:
print("Found keywords",[(kw.arg, literal_eval(kw.value)) for kw in kws])
else:
print([literal_eval(val) for val in node.args])
输出:
[['apple', 'pear', 6], [], ['a', 'b'], [4, 5, 6]]
['apple', 'pear', 6]
('Found keywords', [('a', 1), ('b', 2), ('c', 3)])
['a', 'b']
[4, 5, 6]
使用 ast.Nodevisitor 查找所有 Call 对象将 return 在所有函数中对 "foobar" 的所有调用:
from ast import parse, NodeVisitor, literal_eval
import importlib
import inspect
mod = "test"
mod = importlib.import_module(mod)
p = parse(inspect.getsource(mod))
class FindCall(NodeVisitor):
def __init__(self, *args):
if len(args) < 1:
raise ValueError("Must supply at least ine target function")
self.result = {arg: []for arg in args}
def visit_Call(self, node):
if node.func.id in self.result:
self.result[node.func.id].append(map(literal_eval, node.args))
# visit the children
self.generic_visit(node)
fc = FindCall("foobar")
fc.visit(p)
print(fc.result)
输出:
from pprint import pprint as pp
pp(fc.result)
{'foobar': [['apple', 'pear', 6],
[1, 2, 3],
[4, 5, 6],
['a', 'b'],
['orange', 'tomatoe', 6],
[10, 20, 30],
[40, 50, 60],
['c', 'd']],
'other_method': [['foo', 'bar', 'foobar']]}
您可以再次添加对 kwargs 的搜索,并且只搜索特定的函数。