web-dev-qa-db-fra.com

Comment obtenir le nom de la classe de l'appelant dans une fonction d'une autre classe en python?

Mon objectif est de stimuler le diagramme de séquence d'une application pour cela. J'ai besoin des informations sur un appelant et des noms de classe appelés au moment de l'exécution. Je parviens à récupérer la fonction appelant mais je ne parviens pas à obtenir un nom de classe d'appelant?

#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()

Lorsque j'ai imprimé la pile, il n'y avait aucune information sur la classe d'appelant. Est-il donc possible de récupérer la classe de l'appelant pendant l'exécution?

21
Kaushik

Eh bien, après quelques recherches à l’Invite, voici ce que j’obtiens:

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

print("I was called by {}.{}()".format(str(calling_class), calling_code_name))
# => I was called by A.a()

Lorsque invoqué:

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

étant donné le fichier 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__
    the_method = stack[1][0].f_code.co_name
    print("  I was called by {}.{}()".format(str(the_class), the_method))

A().a()

Vous ne savez pas comment il se comportera lorsqu'il est appelé par autre chose qu'un objet.

30
brice

Utilisation de la réponse de Python: Comment récupérer les informations de classe d’un objet 'frame'?

Je reçois quelque chose comme ça ...

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

ce qui me donne la sortie suivante:

Hello
dude
<class '__main__.A'>

clairement, cela renvoie une référence à la classe elle-même. Si vous voulez le nom de la classe, vous pouvez l'obtenir à partir de l'attribut __name__.

Malheureusement, cela ne fonctionnera pas pour les méthodes de classe ou statiques ...

4
mgilson

Cela enfreint peut-être certains protocoles de programmation Python, mais si Bad est toujours va vérifier la classe de l'appelant, pourquoi ne pas lui transmettre le __class__ de l'appelant dans le cadre de l'appel?

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

Résultat:

Hello
dude
Calling class: __main__.A

S'il s'agit d'une mauvaise forme et que vous utilisez inspect comme méthode privilégiée pour obtenir le cours, veuillez expliquer pourquoi. J'apprends encore sur les concepts plus profonds de Python.

3
Justin S Barrett

Au lieu d'indexer la valeur de retour de inspect.stack (), on pourrait utiliser la méthode inspect.currentframe (), qui évite l'indexation.

prev_frame = inspect.currentframe().f_back
the_class = prev_frame.f_locals["self"].__class__
the_method = prev_frame.f_code.co_name
0
djeongo

Pour stocker le nom d'instance de classe de la pile dans la variable de classe:

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

Ce

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

imprimera:

myClassInstance1
0
Mika72