2010-08-01 59 views
5

我想确定在Python中调用函数的拥有类。例如,我有两个类,ClassA和ClassB。我想知道什么时候classb_instance.call_class_a_method()是class_a.class_a_method的调用者(),使得:如何找到在python中调用函数的类?

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.' 

它好像检查应能够做到这一点,但我不能解决问题。

+0

为什么不把类作为变量传递? – kennytm 2010-08-01 19:29:59

+8

如果您觉得您需要此解决方案,我强烈怀疑您做错了什么。 – 2010-08-01 19:31:42

+0

什么是用例?这很奇怪..你为什么不使用继承?为什么你需要知道谁在打电话?你可以检查堆栈跟踪,但它不漂亮。 – mpen 2010-08-01 19:33:58

回答

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') 

与参与完全没有“类”(虽然类型的字符串的被用作fself的说法是;-)。

我建议依靠内省 - 尤其是野生和毛茸茸的那种,有很多启发,那将需要在这里得到任何半有用的信息 - 任何生产规范要求:重新构建,以避免这种需求。

对于纯粹调试的目的,在这种情况下,你可以走栈,直到你找到一个名为self第一个参数调用函数和内省绑定到该参数名称值的类型 - 但正如我所说这完全是启发式的,因为没有任何东西强迫你的调用者命名他们的第一个参数self当且仅当他们的功能是为某些类的方法。

这种启发式的反省会产生类型的对象OneTwostr,在代码的三个例子我只是给了 - 你看,绝对不是比调试;-)很多其他不错的。

如果你明确地说得更清楚什么你试图通过这种尝试反思,我们当然可以帮助你更好。

+3

哇,我还有很多东西要学。 我想要实现的是一个对象根据它是否被该对象调用将它自己视为另一个对象的子对象。在这里阅读评论,我意识到这种方法多么愚蠢,因为孩子不应该在乎它是否被任何其他对象所拥有。使用父母作为中介从表格中移除了这个内省的整个问题,并无限地简化了问题。 *叹息* – boldfield 2010-08-01 20:08:02

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. 

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

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是duck-typed。

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

+3

我最近发现inspect.stack可以很慢 - 一个宁可使用inspect.currentframe(n)而不是inspect.stack()[n] [0] - (当然,如果一个人在做这个根本就是 - 以前在生产中反对它的考虑大多是有效的 - 除了它在cPython中足够一致) – jsbueno 2010-08-01 22:29:32