J'aimerais convertir un nom de variable python en son équivalent en chaîne de caractères, comme indiqué. Comment faire ?
var = {}
print ??? # Would like to see 'var'
something_else = 3
print ??? # Would print 'something_else'
J'aimerais convertir un nom de variable python en son équivalent en chaîne de caractères, comme indiqué. Comment faire ?
var = {}
print ??? # Would like to see 'var'
something_else = 3
print ??? # Would print 'something_else'
Il existe un scénario d'utilisation pour lequel vous pourriez en avoir besoin. Je n'insinue pas qu'il n'existe pas de meilleurs moyens d'atteindre la même fonctionnalité.
Cela serait utile pour "vider" une liste arbitraire de dictionnaires en cas d'erreur, dans les modes de débogage et dans d'autres situations similaires.
Ce qu'il faudrait, c'est l'inverse de la eval()
fonction :
get_indentifier_name_missing_function()
qui prendrait un nom d'identifiant ('variable', 'dictionnaire', etc.) comme argument, et renverrait une contenant le nom de l'identifiant.
Considérons la situation actuelle suivante :
random_function(argument_data)
Si l'on passe un nom d'identifiant ('fonction', 'variable', 'dictionnaire', etc) argument_data
à un random_function()
(un autre nom d'identifiant), on transmet en fait un identifiant (par exemple : <argument_data object at 0xb1ce10>
) à un autre identifiant (par exemple : <function random_function at 0xafff78>
):
<function random_function at 0xafff78>(<argument_data object at 0xb1ce10>)
D'après ce que j'ai compris, seule l'adresse mémoire est transmise à la fonction :
<function at 0xafff78>(<object at 0xb1ce10>)
Par conséquent, il faudrait passer une chaîne de caractères comme argument à la fonction random_function()
pour que cette fonction ait le nom de l'identifiant de l'argument :
random_function('argument_data')
Dans la fonction random_function()
def random_function(first_argument):
on utilise la chaîne de caractères déjà fournie 'argument_data'
à :
sert de "nom d'identification" (pour l'affichage, l'enregistrement, le fractionnement des chaînes/concat, etc.)
nourrir le eval()
afin d'obtenir une référence à l'identifiant réel, et donc une référence aux données réelles :
print("Currently working on", first_argument)
some_internal_var = eval(first_argument)
print("here comes the data: " + str(some_internal_var))
Malheureusement, cela ne fonctionne pas dans tous les cas. Elle ne fonctionne que si le random_function()
peut résoudre le problème de la 'argument_data'
à un identifiant réel. Par exemple, si argument_data
Le nom de l'identificateur est disponible dans la base de données random_function()
de l'espace de noms.
Ce n'est pas toujours le cas :
# main1.py
import some_module1
argument_data = 'my data'
some_module1.random_function('argument_data')
# some_module1.py
def random_function(first_argument):
print("Currently working on", first_argument)
some_internal_var = eval(first_argument)
print("here comes the data: " + str(some_internal_var))
######
Les résultats attendus sont les suivants :
Currently working on: argument_data
here comes the data: my data
Parce que argument_data
n'est pas disponible dans la base de données random_function()
ce qui aurait pour effet de créer un espace de noms :
Currently working on argument_data
Traceback (most recent call last):
File "~/main1.py", line 6, in <module>
some_module1.random_function('argument_data')
File "~/some_module1.py", line 4, in random_function
some_internal_var = eval(first_argument)
File "<string>", line 1, in <module>
NameError: name 'argument_data' is not defined
Considérons maintenant l'utilisation hypothétique d'un get_indentifier_name_missing_function()
qui se comporterait comme décrit ci-dessus.
Voici un code Python 3.0 factice : .
# main2.py
import some_module2
some_dictionary_1 = { 'definition_1':'text_1',
'definition_2':'text_2',
'etc':'etc.' }
some_other_dictionary_2 = { 'key_3':'value_3',
'key_4':'value_4',
'etc':'etc.' }
#
# more such stuff
#
some_other_dictionary_n = { 'random_n':'random_n',
'etc':'etc.' }
for each_one_of_my_dictionaries in ( some_dictionary_1,
some_other_dictionary_2,
...,
some_other_dictionary_n ):
some_module2.some_function(each_one_of_my_dictionaries)
# some_module2.py
def some_function(a_dictionary_object):
for _key, _value in a_dictionary_object.items():
print( get_indentifier_name_missing_function(a_dictionary_object) +
" " +
str(_key) +
" = " +
str(_value) )
######
Les résultats attendus sont les suivants :
some_dictionary_1 definition_1 = text_1
some_dictionary_1 definition_2 = text_2
some_dictionary_1 etc = etc.
some_other_dictionary_2 key_3 = value_3
some_other_dictionary_2 key_4 = value_4
some_other_dictionary_2 etc = etc.
......
......
......
some_other_dictionary_n random_n = random_n
some_other_dictionary_n etc = etc.
Malheureusement, get_indentifier_name_missing_function()
ne verrait pas les noms d'identificateurs "originaux" ( some_dictionary_
, some_other_dictionary_2
, some_other_dictionary_n
). Il ne verrait que les a_dictionary_object
nom de l'identifiant.
Le résultat réel serait donc plutôt le suivant :
a_dictionary_object definition_1 = text_1
a_dictionary_object definition_2 = text_2
a_dictionary_object etc = etc.
a_dictionary_object key_3 = value_3
a_dictionary_object key_4 = value_4
a_dictionary_object etc = etc.
......
......
......
a_dictionary_object random_n = random_n
a_dictionary_object etc = etc.
Ainsi, l'inverse de la eval()
ne sera pas très utile dans ce cas.
Actuellement, c'est ce qu'il faudrait faire :
# main2.py same as above, except:
for each_one_of_my_dictionaries_names in ( 'some_dictionary_1',
'some_other_dictionary_2',
'...',
'some_other_dictionary_n' ):
some_module2.some_function( { each_one_of_my_dictionaries_names :
eval(each_one_of_my_dictionaries_names) } )
# some_module2.py
def some_function(a_dictionary_name_object_container):
for _dictionary_name, _dictionary_object in a_dictionary_name_object_container.items():
for _key, _value in _dictionary_object.items():
print( str(_dictionary_name) +
" " +
str(_key) +
" = " +
str(_value) )
######
eval()
si l'identifiant du nom est disponible dans l'espace de noms actuel.eval()
ne serait pas utile dans les cas où le nom de l'identificateur n'est pas "vu" directement par le code appelant. Par exemple, à l'intérieur de toute fonction appelée.Pour ce faire, il suffit de transmettre à la fois l'élément 'string'
et eval('string')
à la fonction appelée en même temps. Je pense qu'il s'agit de la manière la plus "générale" de résoudre ce problème de la poule aux œufs d'or pour des fonctions, des modules et des espaces de noms arbitraires, sans avoir recours à des solutions d'urgence. Le seul inconvénient est l'utilisation de la méthode eval()
ce qui peut facilement conduire à un code non sécurisé. Il faut veiller à ne pas alimenter le eval()
avec à peu près n'importe quoi, en particulier avec des données externes non filtrées.
J'ai cherché cette question parce que je voulais qu'un programme Python imprime des instructions d'affectation pour certaines des variables du programme. Par exemple, il pourrait afficher "foo = 3, bar = 21, baz = 432". La fonction d'impression aurait besoin des noms de variables sous forme de chaînes de caractères. J'aurais pu fournir à mon code les chaînes de caractères "foo", "bar" et "baz", mais j'avais l'impression de me répéter. Après avoir lu les réponses précédentes, j'ai élaboré la solution ci-dessous.
La fonction globals() se comporte comme un dict avec des noms de variables (sous forme de chaînes) comme clés. Je voulais récupérer dans globals() la clé correspondant à la valeur de chaque variable. La méthode globals().items() renvoie une liste de tuples ; dans chaque tuple, le premier élément est le nom de la variable (sous forme de chaîne) et le second est la valeur de la variable. Ma fonction variablename() recherche dans cette liste le(s) nom(s) de la variable qui correspond(ent) à la valeur de la variable dont j'ai besoin sous forme de chaîne de caractères.
La fonction itertools.ifilter() effectue la recherche en testant chaque tuple de la liste globals().items() avec la fonction lambda x: var is globals()[x[0]]
. Dans cette fonction, x est le tuple testé ; x[0] est le nom de la variable (sous forme de chaîne) et x[1] est la valeur. La fonction lambda teste si la valeur de la variable testée est la même que la valeur de la variable passée à variablename(). En fait, en utilisant la fonction is
la fonction lambda teste si le nom de la variable testée est lié exactement au même objet que la variable passée à variablename(). Si c'est le cas, le tuple passe le test et est retourné par ifilter().
La fonction itertools.ifilter() renvoie en fait un itérateur qui ne renvoie aucun résultat tant qu'il n'est pas appelé correctement. Pour qu'elle soit appelée correctement, je l'ai placée à l'intérieur d'une compréhension de liste [tpl[0] for tpl ... globals().items())]
. La compréhension de la liste n'enregistre que le nom de la variable tpl[0]
en ignorant la valeur de la variable. La liste créée contient un ou plusieurs noms (sous forme de chaînes) liés à la valeur de la variable passée à variablename().
Dans les utilisations de variablename() présentées ci-dessous, la chaîne souhaitée est renvoyée sous la forme d'un élément d'une liste. Dans de nombreux cas, il s'agit du seul élément de la liste. Toutefois, si la même valeur est attribuée à un autre nom de variable, la liste sera plus longue.
>>> def variablename(var):
... import itertools
... return [tpl[0] for tpl in
... itertools.ifilter(lambda x: var is x[1], globals().items())]
...
>>> var = {}
>>> variablename(var)
['var']
>>> something_else = 3
>>> variablename(something_else)
['something_else']
>>> yet_another = 3
>>> variablename(something_else)
['yet_another', 'something_else']
Tant qu'il s'agit d'une variable et non d'une seconde classe, cela fonctionne pour moi :
def print_var_name(variable):
for name in globals():
if eval(name) == variable:
print name
foo = 123
print_var_name(foo)
>>>foo
cela se produit pour les membres de la classe :
class xyz:
def __init__(self):
pass
member = xyz()
print_var_name(member)
>>>member
et ceci pour les classes (à titre d'exemple) :
abc = xyz
print_var_name(abc)
>>>abc
>>>xyz
Ainsi, pour les classes, il vous donne le nom ET les propriétés.
S'il vous plaît éditer votre message pour des questions de formatage. Il est difficile de comprendre ce que vous dites.
C'est un réel plaisir de lire un billet qui répond à la question sans s'acharner sur la raison pour laquelle la question est posée.
Notez qu'il est possible de lier la même valeur à plusieurs noms. Dans ce cas, le code ci-dessus imprimera plusieurs noms. Il n'y a aucun moyen de savoir quel est le "bon" nom.
Ce n'est pas possible.
En Python, il n'existe pas vraiment de "variable". Ce que Python a vraiment, ce sont des "noms" auxquels peuvent être liés des objets. L'objet ne fait aucune différence quant aux noms auxquels il peut être lié, s'il y en a. Il peut être lié à des dizaines de noms différents, ou à aucun. Il peut être lié à des dizaines de noms différents, ou à aucun.
Prenons l'exemple suivant :
foo = 1
bar = 1
baz = 1
Supposons maintenant que vous disposiez de l'objet entier de valeur 1 et que vous souhaitiez remonter le temps pour trouver son nom. Qu'allez-vous imprimer ? Trois noms différents sont liés à cet objet, et tous sont également valides.
En Python, un nom est un moyen d'accéder à un objet, il n'y a donc aucun moyen de travailler directement avec les noms. Il existe peut-être un moyen astucieux de pirater les bytecodes Python pour obtenir la valeur du nom, mais il s'agit au mieux d'un tour de passe-passe.
Si vous savez que vous voulez print foo
pour imprimer "foo"
vous pouvez tout aussi bien vous contenter d'exécuter print "foo"
en premier lieu.
EDIT : J'ai légèrement modifié la formulation pour la rendre plus claire. Voici également un exemple encore plus parlant :
foo = 1
bar = foo
baz = foo
En pratique, Python réutilise le même objet pour les entiers ayant des valeurs communes comme 0 ou 1, de sorte que le premier exemple devrait lier le même objet aux trois noms. Mais cet exemple est clair comme de l'eau de roche : le même objet est lié à foo, bar et baz.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
1 votes
Pourriez-vous préciser ce que vous essayez de faire ? Il semble que vous demandiez comment résoudre un problème de la mauvaise manière. Il y a aussi une question similaire, mais à propos de Ruby stackoverflow.com/questions/58482/ruby-get-a-variables-name
1 votes
J'ai vérifié cette question car, en utilisant RPy2, je veux passer une variable Python avec un nom R éponyme. Un exemple inutile (mais proche de mon application) :
def to_R( py_var ): r.assign( 'py_var', py_var )
pour assigner les données de (Py) py_var à l'environnement R et avoir le même nom. Ce serait utile pour moi de le faire à la place,r.assign( py_var.stringof, py_var )
a la D puisque le nom de la variable passée à ma fnto_r
n'est pas nécessairementpy_var
.4 votes
L'une des façons de l'utiliser est lorsqu'une déclaration Assert échoue. Vous pouvez fournir à l'utilisateur le nom exact de la variable en question tout en conservant votre code générique, par exemple AssertionError : 'something_else' must be a number greater than 5 (erreur d'affirmation : 'quelque chose_autre' doit être un nombre supérieur à 5). Vous pouvez alors tester chaque variable qui doit être supérieure à 5 et obtenir le nom de la variable dans le message AssertionError.
0 votes
Heureusement qu'il existe une question sur la façon de faire cela en Ruby !