39

我的目标是为此创建一个应用程序的序列图,我需要在运行时获取有关调用者和被调用者类名的信息。我可以成功检索调用者函数但无法获取调用者类名?

#Scenario caller.py:

import inspect

class A:

    def Apple(self):
        print "Hello"
        b=B()
        b.Bad()



class B:

    def Bad(self):
        print"dude"
        print inspect.stack()


a=A()
a.Apple()

当我打印堆栈时,没有关于调用者类的信息。那么是否可以在运行时检索调用者类?

4

6 回答 6

55

好吧,在对提示进行了一些挖掘之后,这就是我得到的:

stack = inspect.stack()
the_class = stack[1][0].f_locals["self"].__class__.__name__
the_method = stack[1][0].f_code.co_name

print("I was called by {}.{}()".format(the_class, the_method))
# => I was called by A.a()

调用时:

➤ python test.py
A.a()
B.b()
  I was called by A.a()

给定文件test.py

import inspect

class A:
  def a(self):
    print("A.a()")
    B().b()

class B:
  def b(self):
    print("B.b()")
    stack = inspect.stack()
    the_class = stack[1][0].f_locals["self"].__class__.__name__
    the_method = stack[1][0].f_code.co_name
    print("  I was called by {}.{}()".format(the_class, the_method))

A().a()

不确定从对象以外的其他对象调用时它的行为方式。

于 2013-06-12T12:33:46.597 回答
7

使用Python 的答案:如何从“框架”对象中检索类信息?

我得到这样的东西......

import inspect

def get_class_from_frame(fr):
  args, _, _, value_dict = inspect.getargvalues(fr)
  # we check the first parameter for the frame function is
  # named 'self'
  if len(args) and args[0] == 'self':
    # in that case, 'self' will be referenced in value_dict
    instance = value_dict.get('self', None)
    if instance:
      # return its class
      return getattr(instance, '__class__', None)
  # return None otherwise
  return None


class A(object):

    def Apple(self):
        print "Hello"
        b=B()
        b.Bad()

class B(object):

    def Bad(self):
        print"dude"
        frame = inspect.stack()[1][0]
        print get_class_from_frame(frame)


a=A()
a.Apple()

这给了我以下输出:

Hello
dude
<class '__main__.A'>

显然,这会返回对类本身的引用。如果您想要类的名称,可以从__name__属性中获取。

不幸的是,这不适用于类或静态方法......

于 2013-06-12T12:38:51.453 回答
4

也许这破坏了一些 Python 编程协议,但是如果 Bad总是要检查调用者的类,为什么不将调用者的类作为调用的__class__一部分传递给它呢?

class A:

    def Apple(self):
        print "Hello"
        b=B()
        b.Bad(self.__class__)



class B:

    def Bad(self, cls):
        print "dude"
        print "Calling class:", cls


a=A()
a.Apple()

结果:

Hello
dude
Calling class: __main__.A

如果这是不好的形式,并且使用inspect真的是获取调用者课程的首选方式,请解释原因。我仍在学习更深层次的 Python 概念。

于 2013-06-12T12:43:18.600 回答
4

可以使用方法inspect.currentframe() 代替索引inspect.stack() 的返回值,从而避免索引。

prev_frame = inspect.currentframe().f_back
the_class = prev_frame.f_locals["self"].__class__
the_method = prev_frame.f_code.co_name
于 2018-11-27T00:13:11.337 回答
1

蟒蛇 3.8

import inspect


class B:
    def __init__(self):
        if (parent := inspect.stack()[1][0].f_locals.get('self', None)) and isinstance(parent, A):
            parent.print_coin()


class A:
    def __init__(self, coin):
        self.coin: str = coin
        B()

    def print_coin(self):
        print(f'Coin name: {self.coin}')


A('Bitcoin')
于 2020-04-07T10:12:10.147 回答
0

要将类实例名称从堆栈存储到类变量:

import inspect

class myClass():

    caller = ""

    def __init__(self):
        s = str(inspect.stack()[1][4]).split()[0][2:]
        self.caller = s

    def getInstanceName(self):
        return self.caller

myClassInstance1 = myClass()
print(myClassInstance1.getInstanceName())

将打印:

myClassInstance1
于 2018-04-30T06:32:15.170 回答