Est-il possible de récupérer des informations de classe à partir d'un objet frame? Je sais comment obtenir le fichier (frame.f_code.co_filename), la fonction (frame.f_code.co_name) et le numéro de ligne (frame.f_lineno), mais j'aimerais pouvoir aussi obtenir le nom de la classe de l'objet actif instance de l'image (ou None si elle n'est pas dans une instance).Python: Comment récupérer des informations de classe à partir d'un objet 'frame'?
Répondre
Je ne crois pas que, au niveau de l'objet frame, il y ait un moyen de trouver l'objet réel de la fonction python qui a été appelé.
Cependant, si votre code repose sur la convention commune: nommer le paramètre d'instance d'une méthode self
, vous pouvez effectuer les opérations suivantes:
def get_class_from_frame(fr):
import inspect
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
Si vous ne souhaitez pas utiliser getargvalues
, vous pouvez utiliser directement frame.f_locals
au lieu de value_dict
et frame.f_code.co_varnames[:frame.f_code.co_argcount]
au lieu de args
.
Gardez à l'esprit que cela est encore se fondant uniquement sur la convention, il est donc pas portable, et sujette aux erreurs:
- si une utilisation de la fonction non-méthode
self
comme premier nom de paramètre,get_class_from_frame
sera à tort retourne la classe du premier paramètre. - il peut être trompeur lorsque vous travaillez avec des descripteurs (il renverra la classe du descripteur, pas de l'instance en cours d'accès).
@classmethod
et@staticmethod
ne prend pas un paramètreself
et sont implémentés avec des descripteurs.- et sûrement beaucoup plus
Selon exactement ce que vous voulez faire, vous voudrez peut-être prendre un certain temps pour creuser plus profondément et de trouver des solutions de contournement pour toutes ces questions (vous pouvez vérifier la fonction de cadre existent dans la retourné la classe et partager la même source, la détection des appels descripteur est possible, même pour les méthodes de classe, etc.)
Ceci est un peu plus court, mais fait à peu près la même chose. Renvoie None si le nom de la classe n'est pas disponible.
def get_class_name():
f = sys._getframe(1)
try:
class_name = f.f_locals['self'].__class__.__name__
except KeyError:
class_name = None
return class_name
Bonne réponse! Mieux encore, vous pourriez faire '' f.f_locals ['__ class __'] .__ name__'', qui devrait aussi couvrir les cas '' @ classmethod'' et '' @ staticmethod''. –
@LucioPaiva qui ne fonctionne pas. Il n'y a pas de clé "__class __" dans f_locals. – Pithikos
Je suis juste tombé sur ce post car j'étais confronté au même problème. Cependant, je ne considérais pas la méthode «self» comme une solution acceptable pour toutes les raisons déjà mentionnées.
Le code suivant illustre une approche différente: étant donné un objet frame, il recherche les globals pour un objet avec un nom de membre correspondant et un bloc de code. La recherche n'est pas exhaustive, il est donc possible que toutes les classes ne soient pas découvertes, mais les classes trouvées devraient être celles que nous recherchons parce que nous vérifions les codes correspondants.
objet du code est de préfixer un nom de fonction avec son nom de classe, se trouve:
def get_name(frame):
code = frame.f_code
name = code.co_name
for objname, obj in frame.f_globals.iteritems():
try:
assert obj.__dict__[name].func_code is code
except Exception:
pass
else: # obj is the class that defines our method
name = '%s.%s' % (objname, name)
break
return name
Notez l'utilisation de __dict__
au lieu de getattr
pour empêcher la capture des classes dérivées. Notez également qu'une recherche globale peut être évitée si self = frame.f_locals['self']; obj = self.__class__
donne une correspondance, ou obj in self.__class__.__bases__
ou plus profond, donc il y a certainement de la place pour l'optimisation/l'hybridation.
Si une méthode est une méthode de classe, la classe sera le premier argument. Cela affiche le type du premier argument si présent pour chaque trame de pile appelante:
def some_method(self):
for f in inspect.getouterframes(inspect.currentframe()):
args, _,_, local_dict = inspect.getargvalues(f[0])
if args:
first_arg = args[0]
first_value = local_dict[first_arg]
print(type(first_value).__name__)
Merci pour votre réponse, Clément; c'est détaillé et réfléchi. J'espère toujours obtenir plus qu'une seule réponse! Mais sinon, celui-ci devra suffire ... –
OK, attendu assez longtemps. C'est une bonne réponse! J'avais espéré un meilleur soutien des structures de cadre, mais c'est ce que c'est. Merci encore, Clément! –
Pour en ajouter un à la liste, veillez à ce que 'self' soit une instance d'une classe dérivée, qui pourrait ne pas être celle qui nous intéresse. – gertjan