如何在python中找到调用函数类?

时间:2010-08-01 19:28:00

标签: python

我试图在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()
输出将是:

'ClassB is not calling.'
'ClassB is calling.'

似乎 inspect 应该可以做到这一点,但我不知道如何。

4 个答案:

答案 0 :(得分:5)

好吧,如果你想遍历调用堆栈并找到哪个类(如果有的话)确实调用它,那么它很简单:

def class_a_method(self):
    stack = inspect.stack()
    frame = stack[1][0]
    caller = frame.f_locals.get('self', None)

如果要检查调用者是否属于ClassB类型,则应使用isinstance(caller, ClassB)而不是__class__上的比较。然而,这通常是非pythonic,因为python是鸭子类型。

正如其他人所说,很可能您的应用需要重新设计以避免使用inspect.stack。它的CPython实现功能,并不保证在其他Python实现中出现。此外,它只是错误的事情。

答案 1 :(得分:4)

函数不“拥有”一个类 - 一个或多个类可能(但不必)引用给定的函数对象,例如:

def f(self): return g()

class One(object): bah = f

class Two(object): blup = f

def g(): ...

One.bahTwo.blup都被设置为对同一个函数对象f的引用(当在类或它们的实例上访问时变成未绑定或绑定的方法对象,但是这样做了堆栈中没有痕迹)。所以,堆栈

One().f()

VS

Two().f()
从在任何一种情况下调用的g()看来,确实很难区分 - 例如,由于,例如,

f('blah bloh blup')

根本没有涉及“类”(尽管用作f self参数的字符串的 type 将是; - )。

我建议依靠内省 - 尤其是狂野和毛茸茸的类型,需要大量的启发式方法,以获取任何生产中的任何半有用信息代码要求:重新构建以避免这种需求。

对于纯调试目的,在这种情况下,您可以遍历堆栈,直到找到一个名为self的第一个参数的调用函数,并且内省绑定到该值的值的类型参数名称 - 但正如我所提到的那样,这完全具有启发性,因为当且仅当它们的函数是某些类中的方法时,才会强制您的调用者命名它们的第一个参数self

这样的启发式内省会产生类型对象OneTwostr,在我刚给出的三个代码示例中 - 如你所见,绝对不是很好比调试; - )。

如果你通过这次尝试的内省更准确地澄清你想要完成的 ,我们当然可以更好地帮助你。

答案 2 :(得分:0)

class ClassA( object ):
    def class_a_method( self ):
        if any( "call_class_a_method" in tup for tup in inspect.stack( ) ):
            print( 'ClassB is calling.' )
        else:
            print( 'ClassB is not calling.' )
# ClassB is not calling.
# ClassB is calling.

为什么你真的需要这个?这是一个讨厌的黑客,因为它不是你应该做的事情。

答案 3 :(得分:0)

通常调用者知道并且应该使用适当的参数,而不是在被调用的类中做魔术。

您是否需要工厂类/功能来记录类或为其编写装饰器?