我在一个调用方法列表的类中有一个方法def testing(self)
。我需要知道是否有任何方法可以获得方法中调用的方法总数,然后分别访问每个方法。
def testing(self):
self.method1()
self.method2()
self.method3()
return
def method1(self):
"""DO WORK"""
return
def method2(self):
"""DO WORK"""
return
def method3(self):
"""DO WORK"""
return
答案 0 :(得分:1)
可靠且稳健吗?否。
有两种基本方法:
模拟至少具有潜在的破坏性,而且它很脆弱,而且可能很复杂。但最大的问题是它只能在所调用的路径上找到方法调用。例如,让我们说你写了这个:
def testing(self):
if self.method1():
return self.method2()
else:
return self.method3(self.method4())
显然,没有电话会找到所有四个方法调用。
或者:
def testing(self):
return 2 / self.method1()
除非您事先知道method1
必须在此上下文中返回一个数字,否则您将在此处获得TypeError
。但如果你知道这一点,你可能已经知道在这种情况下调用method1
,所以你的问题甚至不存在。
无论如何,因为模拟在概念层面上已经足够困难而不必处理所有实现难题,正确的方法是使用第三方模块,如Michele d'Amico's answer所示。但是如果你想了解它是如何工作的,你可以自己快速建立一些东西:
def mock(method, *args, **kwargs):
obj = method.__self__
_old_getattribute = type(obj).__getattribute__
methods = []
def _new_getattribute(self, attr):
methods.append(attr)
type(obj).__getattribute__ = _new_getattribute
try:
method(*args, **kwargs)
except Exception as e:
print 'Ignoring {}: {}'.format(type(e), e)
type(obj).__getattribute__ = _old_getattribute
return [name for name in methods if callable(getattr(obj, name))]
methods = mock(self.testing)
除了上面提到的问题之外,这本身就假定在方法调用过程中self
上查找的任何内容实际存在,并且任何可调用的内容(包括例如{{1}或者在实例属性中填充的常规函数)是一种方法。你几乎必须仔细思考所有这些问题,决定你想要什么,并实现它。
同时,有多种方法可以查看代码。您可以解析源代码(例如,使用inspect.getsource
),或者您可以对staticmethod
中的字节码进行grub。 (Bytecode当然是不可移植的。)但幸运的是,stdlib有两个模块来帮助你:dis
来反汇编字节码,或ast
模块来解析源代码。 testing.__code__.co_code
的2.x版本使用起来有点笨拙;它没有给你任何方法来迭代字节码并访问它们的参数等。你仍然可以通过解析字符串输出或使用各种第三方模块来完成它。
无论如何,你需要提出一些关于什么算作"方法调用的规则"并编写代码来识别该模式。当然,模拟版本也是如此,但是这个版本更加明显。
以下是dis
的示例,该示例可以查找直接在ast
之外访问的任何内容:
self