我试图在python中确定一个调用函数的拥有类.例如,我有两个类,ClassA和ClassB.我想知道classb_instance.call_class_a_method()是class_a.class_a_method()的调用者,这样:
class ClassA(object):
def class_a_method(self):
# Some unknown process would occur here to
# define caller.
if caller.__class__ == ClassB:
print 'ClassB is calling.'
else:
print 'ClassB is not calling.'
class ClassB(object):
def __init__(self):
self.class_a_instance = ClassA()
def call_class_a_method(self):
self.class_a_instance.class_a_method()
classa_instance = ClassA()
classa_instance.class_a_method()
classb_instance = ClassB()
classb_instance.call_class_a_method()
Run Code Online (Sandbox Code Playgroud)
输出将是:
'ClassB is not calling.'
'ClassB is calling.'
Run Code Online (Sandbox Code Playgroud)
似乎检查应该能够做到这一点,但我不知道如何.
好吧,如果你想遍历调用堆栈并找到哪个类(如果有的话)调用它,那么它很简单:
def class_a_method(self):
stack = inspect.stack()
frame = stack[1][0]
caller = frame.f_locals.get('self', None)
Run Code Online (Sandbox Code Playgroud)
如果要检查调用者是否为ClassB类型,则应使用isinstance(caller, ClassB)而不是比较__class__.然而,这通常是非pythonic,因为python是鸭子类型.
正如其他人所说,很可能您的应用需要重新设计以避免使用inspect.stack.它的CPython实现功能,并不保证在其他Python实现中出现.此外,它只是错误的事情.
函数不“拥有”类——一个或多个类可以(但不一定)引用给定的函数对象,例如:
def f(self): return g()
class One(object): bah = f
class Two(object): blup = f
def g(): ...
Run Code Online (Sandbox Code Playgroud)
One.bah和Two.blup都设置为对同一函数对象的引用f(并且在类或其实例上访问时变成未绑定或绑定方法对象,但这不会在堆栈中留下任何痕迹)。所以,堆栈上
One().f()
Run Code Online (Sandbox Code Playgroud)
与
Two().f()
Run Code Online (Sandbox Code Playgroud)
从这g()两种情况下调用的 that 可以看出,确实很难区分——就像由例如,
f('blah bloh blup')
Run Code Online (Sandbox Code Playgroud)
根本不涉及“类”(尽管用作参数的字符串类型是;-)。fself
我建议不要依赖内省——尤其是狂野和毛茸茸的类型,有很多启发式,需要在这里获取任何半有用的信息——对于任何生产代码要求:重新架构以避免这种需要。
出于纯粹的调试目的,在这种情况下,您可以遍历堆栈,直到找到第一个参数名为的调用函数,self并内省绑定到该参数名称的值的类型 - 但正如我提到的,这完全是启发式的,因为没有任何强制self当且仅当它们的函数是某个类中的方法时,调用者才能命名它们的第一个参数。
在我刚刚给出的三个代码示例中,这种启发式内省将产生类型对象One、Two和str,如您所见,除了调试之外,绝对没有其他好处;-)。
如果您通过这次尝试的内省更好地明确了您想要实现的目标,我们当然可以更好地帮助您。