Ce fil explique comment obtenir le nom d'une fonction sous forme de chaîne en Python: Comment obtenir un nom de fonction sous forme de chaîne?
Comment puis-je faire de même pour une variable? Contrairement aux fonctions, les variables Python n'ont pas l' __name__
attribut.
En d'autres termes, si j'ai une variable telle que:
foo = dict()
foo['bar'] = 2
Je recherche une fonction / attribut, par exemple retrieve_name()
pour créer un DataFrame dans Pandas à partir de cette liste , où les noms de colonnes sont donnés par les noms des dictionnaires actuels:
# List of dictionaries for my DataFrame
list_of_dicts = [n_jobs, users, queues, priorities]
columns = [retrieve_name(d) for d in list_of_dicts]
pip3 install python-varname==0.1.5
; importé en utilisantfrom varname import nameof
test = {}
print(varname.nameof(test))
for i in [0]:
print(varname.nameof(test))
la première impression donnetest
, l'impression dans la boucle augmenteVarnameRetrievingError: Callee's node cannot be detected.
v0.2.0
Les seuls objets en Python qui ont des noms canoniques sont des modules, des fonctions et des classes, et bien sûr il n'y a aucune garantie que ce nom canonique ait une signification dans n'importe quel espace de noms après que la fonction ou la classe a été définie ou le module importé. Ces noms peuvent également être modifiés après la création des objets afin qu'ils ne soient pas toujours particulièrement fiables.
Ce que vous voulez faire n'est pas possible sans parcourir récursivement l'arborescence des objets nommés ; un nom est une référence unidirectionnelle à un objet. Un objet Python commun ou de jardin ne contient aucune référence à ses noms. Imaginez si chaque entier, chaque dict, chaque liste, chaque booléen avait besoin de maintenir une liste de chaînes qui représentaient les noms qui y faisaient référence! Ce serait un cauchemar d'implémentation, avec peu d'avantages pour le programmeur.
la source
__name__
peut toujours être modifié, ce qui signifie que le nom «canonique» peut ne pas être un nom pouvant être utilisé pour obtenir l'objet (par exemple lors de la création dynamique de classes).Même si les valeurs des variables ne pointent pas vers le nom, vous avez accès à la liste de chaque variable affectée et à sa valeur, donc je suis étonné qu'une seule personne ait suggéré de faire une boucle là-bas pour rechercher le nom de votre var.
Quelqu'un a mentionné sur cette réponse que vous devrez peut-être parcourir la pile et vérifier les sections locales et globales de tout le monde pour trouver
foo
, mais sifoo
est attribué dans la portée où vous appelez cetteretrieve_name
fonction, vous pouvez utiliserinspect
scurrent frame
pour obtenir toutes ces variables locales .Mon explication est peut-être un peu trop verbeuse (j'aurais peut-être dû utiliser un "toto" moins de mots), mais voici à quoi cela ressemblerait dans le code ( notez que s'il y a plus d'une variable assignée à la même valeur, vous obtenir ces deux noms de variables ):
Si vous appelez cette fonction à partir d'une autre fonction, quelque chose comme:
Et vous voulez le
baz
au lieu debar
, il vous suffira de remonter un peu plus loin. Cela peut être fait en ajoutant un supplément.f_back
lors de l'caller_local_vars
initialisation.Voir un exemple ici: ideone
la source
import hooks
,ironpython
etjython
a, b = 2, 2
,retrieve_name(a)
etretrieve_name(b)
reviendrez tous les deux['a', 'b']
ou['b', 'a']
true
is
def foo(bar): retrieve_name(bar)
retournera toujours bar, mais que faire si vous voulezfoo(baz)
retournerbaz
) au lieu debar
?callers_local_vars
pour aller plus loin en arrière afin de regarder la portée de tout ce qui appellefoo
. Changez la ligne pour êtreinspect.currentframe().f_back.f_back.f_locals.items()
(notez le supplémentf_back
).Avec Python 3.8, on peut simplement utiliser la fonction de débogage f-string:
la source
f'{foo=}'.split('=')[0].split('.')[-1]
Sur python3, cette fonction obtiendra le nom le plus externe de la pile:
C'est utile n'importe où sur le code. Traverse la pile inversée à la recherche du premier match.
la source
retrieve_name(SomeClass.some_attribute)
cela ne fonctionne pas. Pouvez-vous aider davantage à ce sujet?stop_on_error
Je ne crois pas que ce soit possible. Prenons l'exemple suivant:
Les
a
etb
pointent vers le même objet, mais l'objet ne peut pas savoir quelles variables pointent vers lui.la source
Il est utilisé comme ceci:
la source
name(variable=variable)
volonté de sortie['variable']
, et l' utilisationname(variable=another_variable)
sera pas sortie ,['another_variable']
mais plutôt['variable']
.>>> a = []
>>> b = a
>>> name(a=b)
['a']
>>> name(b=a)
['b']
`Voici une approche. Je ne recommanderais pas cela pour quelque chose d'important, car ce sera assez fragile. Mais cela peut être fait.
Créez une fonction qui utilise le
inspect
module pour trouver le code source qui l'a appelé. Ensuite, vous pouvez analyser le code source pour identifier les noms de variables que vous souhaitez récupérer. Par exemple, voici une fonction appeléeautodict
qui prend une liste de variables et renvoie un dictionnaire mappant les noms de variables à leurs valeurs. Par exemple:Donnerait:
Inspecter le code source lui-même est préférable à une recherche dans le
locals()
ouglobals()
parce que cette dernière approche ne vous dit pas quelles variables sont celles que vous souhaitez.En tout cas, voici le code:
L'action se produit dans la ligne avec
inspect.getouterframes
, qui renvoie la chaîne dans le code qui a appeléautodict
.L'inconvénient évident de ce type de magie est qu'elle émet des hypothèses sur la structure du code source. Et bien sûr, cela ne fonctionnera pas du tout s'il est exécuté dans l'interpréteur.
la source
J'ai écrit le paquet sorcellerie pour faire ce genre de magie avec robustesse. Tu peux écrire:
et transmettez-le au constructeur de dataframe. C'est équivalent à:
la source
Si vous vouliez écrire votre propre fonction, cela pourrait être fait de telle sorte que vous puissiez vérifier une variable définie dans les locaux puis vérifier les globaux. Si rien n'est trouvé, vous pouvez comparer sur id () pour voir si la variable pointe vers le même emplacement en mémoire.
Si votre variable est dans une classe, vous pouvez utiliser className. dict .keys () ou vars (self) pour voir si votre variable a été définie.
la source
locals
etglobals
... et vous risquez de vous tromper si aucun nom n'existe réellement. C'est une tonne de travail sans gain utile réel.En Python, les mots
def
-class
clés et lieront un nom spécifique à l'objet qu'ils définissent (fonction ou classe). De même, les modules reçoivent un nom parce qu'ils sont appelés quelque chose de spécifique dans le système de fichiers. Dans les trois cas, il existe une manière évidente d'attribuer un nom «canonique» à l'objet en question.Cependant, pour d'autres types d'objets, un tel nom canonique peut simplement ne pas exister . Par exemple, considérez les éléments d'une liste. Les éléments de la liste ne sont pas nommés individuellement et il est tout à fait possible que la seule façon de s'y référer dans un programme soit d'utiliser des index de liste sur la liste contenante. Si une telle liste d'objets était transmise à votre fonction, vous ne pourriez pas attribuer d'identificateurs significatifs aux valeurs.
Python n'enregistre pas le nom sur le côté gauche d'une affectation dans l'objet affecté car:
Ainsi, par exemple, les fonctions définies avec
lambda
auront toujours le "nom"<lambda>
, plutôt qu'un nom de fonction spécifique.La meilleure approche serait simplement de demander à l'appelant de transmettre une liste (facultative) de noms. Si taper le
'...','...'
est trop compliqué, vous pouvez accepter par exemple une seule chaîne contenant une liste de noms séparés par des virgules (comme lenamedtuple
fait).la source
Je pense que c'est tellement difficile de faire cela en Python à cause du simple fait que vous ne saurez jamais le nom de la variable que vous utilisez. Donc, dans son exemple, vous pourriez faire:
Au lieu de:
la source
juste une autre façon de le faire en fonction du contenu de la variable d'entrée:
(il renvoie le nom de la première variable qui correspond à la variable d'entrée, sinon None. On peut le modifier pour obtenir tous les noms de variables qui ont le même contenu que la variable d'entrée)
la source
Cette fonction affichera le nom de la variable avec sa valeur:
la source
locals () - Renvoie un dictionnaire contenant les variables locales de la portée actuelle. en itérant dans ce dictionnaire, nous pouvons vérifier la clé qui a une valeur égale à la variable définie, le simple fait d'extraire la clé nous donnera le texte de la variable au format chaîne.
depuis (après quelques changements) https://www.tutorialspoint.com/How-to-get-a-variable-name-as-a-string-in-Python
la source
J'ai une méthode, et même si ce n'est pas la plus efficace ... ça marche! (et cela n'implique aucun module sophistiqué).
Fondamentalement , il compare votre ID de variable à globals () les IDs de variables , puis retourne le nom du match.
la source
Si l'objectif est de vous aider à garder une trace de vos variables, vous pouvez écrire une fonction simple qui étiquette la variable et renvoie sa valeur et son type. Par exemple, supposons que i_f = 3.01 et que vous l'arrondissiez à un entier appelé i_n à utiliser dans un code, puis que vous ayez besoin d'une chaîne i_s qui ira dans un rapport.
Cela s'imprime dans la fenêtre à chaque appel à des fins de débogage et génère également une chaîne pour le rapport écrit. Le seul inconvénient est que vous devez taper la variable deux fois chaque fois que vous appelez la fonction.
Je suis un débutant en Python et j'ai trouvé ce moyen très utile de consigner mes efforts pendant que je programme et que j'essaie de gérer tous les objets en Python. Un défaut est que whatis () échoue s'il appelle une fonction décrite en dehors de la procédure où elle est utilisée. Par exemple, int (i_f) était un appel de fonction valide uniquement parce que la fonction int est connue de Python. Vous pouvez appeler whatis () en utilisant int (i_f ** 2), mais si pour une raison étrange vous choisissez de définir une fonction appelée int_squared, elle doit être déclarée dans la procédure où whatis () est utilisé.
la source
Peut-être que cela pourrait être utile:
La fonction parcourt la liste des ID de valeurs de la portée globale (l'espace de noms peut être modifié), trouve l'index de la variable ou de la fonction voulue / requise en fonction de son ID, puis renvoie le nom de la liste des noms globaux en fonction sur l'index acquis.
la source
La méthode suivante ne retournera pas le nom de la variable, mais en utilisant cette méthode, vous pouvez créer facilement un bloc de données si la variable est disponible dans la portée globale.
la source
Pour les constantes, vous pouvez utiliser une énumération, qui prend en charge la récupération de son nom.
la source
J'essaie d'obtenir le nom des locaux inspectés, mais il ne peut pas traiter var aime a [1], b.val. Après cela, j'ai eu une nouvelle idée - obtenir le nom de var à partir du code, et je l'essaye avec succès! code comme ci-dessous:
la source
Vous pouvez essayer ce qui suit pour récupérer le nom d'une fonction que vous avez définie (ne fonctionne pas pour les fonctions intégrées cependant):
la source