Je voudrais convertir un nom de variable python en équivalent de chaîne, comme indiqué. Des idées comment?
var = {}
print ??? # Would like to see 'var'
something_else = 3
print ??? # Would print 'something_else'
Il existe un scénario d'utilisation dans lequel vous pourriez en avoir besoin. Je ne sous-entends pas qu'il n'y a pas de meilleurs moyens ou d'obtenir 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 autres situations similaires.
Ce qui serait nécessaire est l’inverse de la fonction eval()
:
get_indentifier_name_missing_function()
qui prendrait un nom d’identifiant ('variable', 'dictionnaire', etc.) en tant qu’argument et renverrait une chaîne contenant le nom de l’identifiant.
Considérez la situation actuelle suivante:
random_function(argument_data)
Si l'on passe un nom d'identifiant ('fonction', 'variable', 'dictionnaire', etc.) argument_data
à random_function()
(autre nom d'identifiant), on passe 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>)
De ma compréhension, seule l'adresse mémoire est transmise à la fonction:
<function at 0xafff78>(<object at 0xb1ce10>)
Par conséquent, il faudrait passer une chaîne en tant qu'argument à random_function()
pour que cette fonction ait le nom d'identifiant de l'argument:
random_function('argument_data')
Dans la random_function ()
def random_function(first_argument):
, on utiliserait la chaîne déjà fournie 'argument_data'
pour:
alimentez la fonction eval()
afin d'obtenir une référence à l'identificateur actuel et, par conséquent, 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. Cela ne fonctionne que si random_function()
peut résoudre la chaîne 'argument_data'
en un identificateur réel. C'est à dire. Si argument_data
nom d'identifiant est disponible dans l'espace de noms de random_function()
.
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 seraient:
Currently working on: argument_data
here comes the data: my data
Étant donné que le nom d'identificateur argument_data
n'est pas disponible dans l'espace de noms de random_function()
, cela produirait à la place:
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
Maintenant, considérons l’utilisation hypotétique d’une get_indentifier_name_missing_function()
qui se comporterait comme décrit ci-dessus.
Voici un code factice pour Python 3.0:.
# 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 seraient:
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'identifiant 'originaux' (some_dictionary_
, some_other_dictionary_2
, some_other_dictionary_n
). Il ne verrait que le nom d'identifiant a_dictionary_object
.
Par conséquent, le résultat réel serait plutôt:
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.
Donc, l'inverse de la fonction eval()
ne sera pas utile dans ce cas.
Actuellement, il faudrait faire ceci:
# 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()
que 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'identifiant n'est pas "vu" directement par le code appelant. Par exemple. à l'intérieur de toute fonction appelée.Cela peut être réalisé en transmettant les 'string'
et eval('string')
à la fonction appelée en même temps. Je pense que c’est la manière la plus générale de résoudre ce problème Egg-chicken à travers des fonctions, modules, espaces de noms arbitraires, sans utiliser de solution de casse à l’angle. Le seul inconvénient est l'utilisation de la fonction eval()
qui peut facilement conduire à un code non sécurisé. Il faut veiller à ne pas alimenter la fonction eval()
avec à peu près tout, en particulier des données d’entrée externe non filtrées.
J'ai cherché cette question parce que je souhaitais 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 print aurait besoin des noms de variable sous forme de chaîne. J'aurais pu fournir mon code avec les chaînes "foo", "bar" et "baz", mais cela ressemblait à me répéter. Après avoir lu les réponses précédentes, j'ai développé la solution ci-dessous.
La fonction globals () se comporte comme un dict avec des noms de variables (sous la forme de chaînes) comme clés. Je voulais extraire de 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 () cherche dans cette liste le (s) nom (s) de variable correspondant à la valeur de la variable dont j'ai besoin du nom sous forme de chaîne.
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 identique à la valeur de la variable transmise à variablename (). En fait, en utilisant l'opérateur is
, la fonction lambda teste si le nom de la variable testée est lié au même objet que la variable transmise à variablename (). Si c'est le cas, le tuple réussit le test et est renvoyé 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 l'appeler correctement, je l'insère dans une liste de compréhension [tpl[0] for tpl ... globals().items())]
. La compréhension de la liste enregistre uniquement le nom de 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 transmise à variablename ().
Dans les utilisations de variablename () ci-dessous, la chaîne souhaitée est renvoyée sous forme d'élément dans une liste. Dans de nombreux cas, ce sera le seul élément de la liste. Si la même valeur est affecté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']
Ce n'est pas possible.
En Python, il n’existe pas vraiment de "variable". Ce que Python a vraiment, ce sont des "noms" auxquels des objets peuvent être liés. Cela ne fait aucune différence avec les noms d'objet auxquels il pourrait être lié, le cas échéant. Il pourrait être lié à des dizaines de noms différents, voire aucun.
Considérons cet exemple:
foo = 1
bar = 1
baz = 1
Supposons maintenant que l'objet entier ait la valeur 1 et que vous souhaitiez travailler en arrière et trouver son nom. Que voudriez-vous imprimer? Cet objet est lié à trois noms différents 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 pourrait y avoir un moyen astucieux de pirater les bytecodes de Python ou quelque chose pour obtenir la valeur du nom, mais c'est au mieux un tour de passe-passe.
Si vous savez que vous voulez que print foo
imprime "foo"
, vous pouvez aussi simplement exécuter print "foo"
en premier lieu.
EDIT: J'ai légèrement modifié le libellé pour le rendre plus clair. En outre, voici un exemple encore meilleur:
foo = 1
bar = foo
baz = foo
En pratique, Python réutilise le même objet pour les entiers ayant des valeurs communes telles que 0 ou 1, le premier exemple doit donc lier le même objet aux trois noms. Mais cet exemple est limpide: le même objet est lié à foo, bar et baz.
Techniquement, l’information vous est disponible, mais comme d’autres l’ont demandé, comment vous en serviriez-vous judicieusement?
>>> x = 52
>>> globals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__',
'x': 52, '__doc__': None, '__package__': None}
Cela montre que le nom de la variable est présent sous forme de chaîne dans le dictionnaire globals ().
>>> globals().keys()[2]
'x'
Dans ce cas, il s’agit de la troisième clé, mais il n’existe aucun moyen fiable de savoir où un nom de variable donné aboutira.
>>> for k in globals().keys():
... if not k.startswith("_"):
... print k
...
x
>>>
Vous pouvez filtrer les variables système de cette manière, mais vous obtiendrez tous vos propres éléments. Le simple fait d'exécuter ce code ci-dessus a créé une autre variable "k" qui a modifié la position de "x" dans le dict.
Mais c'est peut-être un début utile pour vous. Si vous nous dites à quoi vous voulez que cette capacité, des informations plus utiles pourraient éventuellement être données.
tant qu'il s'agit d'une variable et non d'une seconde classe, cela fonctionne ici 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
ans this pour les classes (à titre d'exemple):
abc = xyz
print_var_name(abc)
>>>abc
>>>xyz
Donc, pour les cours, il vous donne le nom ET les propriétés
Qu'essayez-vous de réaliser? Il n’ya absolument aucune raison de faire ce que vous décrivez et il existe probablement une bien meilleure solution au problème que vous essayez de résoudre.
L'alternative la plus évidente à ce que vous demandez est un dictionnaire. Par exemple:
>>> my_data = {'var': 'something'}
>>> my_data['something_else'] = 'something'
>>> print my_data.keys()
['var', 'something_else']
>>> print my_data['var']
something
Principalement sous forme de .. défi, j'ai implémenté la sortie souhaitée. N'utilisez pas ce code, s'il vous plaît!
#!/usr/bin/env python2.6
class NewLocals:
"""Please don't ever use this code.."""
def __init__(self, initial_locals):
self.prev_locals = list(initial_locals.keys())
def show_new(self, new_locals):
output = ", ".join(list(set(new_locals) - set(self.prev_locals)))
self.prev_locals = list(new_locals.keys())
return output
# Set up
eww = None
eww = NewLocals(locals())
# "Working" requested code
var = {}
print eww.show_new(locals()) # Outputs: var
something_else = 3
print eww.show_new(locals()) # Outputs: something_else
# Further testing
another_variable = 4
and_a_final_one = 5
print eww.show_new(locals()) # Outputs: another_variable, and_a_final_one
Vous devez en quelque sorte faire référence à la variable dont vous souhaitez imprimer le nom. Donc, cela ressemblerait à:
print varname(something_else)
Une telle fonction n’existe pas, mais s’il en existait une, ce serait inutile. Vous devez taper something_else
afin de pouvoir taper des guillemets à gauche et à droite de celui-ci pour afficher le nom sous forme de chaîne:
print "something_else"
Voici une variante succincte qui vous permet de spécifier n'importe quel répertoire ..__ Le problème avec l'utilisation de répertoires pour rechercher n'importe quoi est que plusieurs variables peuvent avoir la même valeur. Donc, ce code retourne une liste de variables possibles.
def varname( var, dir=locals()):
return [ key for key, val in dir.items() if id( val) == id( var)]
Je pense que c'est une solution intéressante et je suppose que vous pouvez obtenir le meilleur. Mais voyez-vous un moyen de gérer les résultats ambigus, votre fonction peut renvoyer? Comme l'opérateur "est" se comporte de manière inattendue avec des entiers variablename-function pourrait donner des résultats ambigus avec une probabilité élevée. Dans mon cas, je voudrais créer un décorateur, qui ajoute une nouvelle variable à une classe par le varialbename que je lui transmets:
def inject(klass, dependency):
klass.__dict__["__"+variablename(dependency)]=dependency
Mais si votre méthode renvoie des résultats ambigus, comment puis-je connaître le nom de la variable que j'ai ajoutée?
var any_var="myvarcontent"
var myvar="myvarcontent"
@inject(myvar)
class myclasss():
def myclass_method(self):
print self.__myvar #I can not be sure, that this variable will be set...
Peut-être que si je vérifierais également la liste locale, je pourrais au moins supprimer la variable "dépendance" de la liste, mais ce ne sera pas un résultat fiable.
Django ne le fait-il pas lors de la génération de noms de champs?
http://docs.djangoproject.com/fr/dev//topics/db/models/#verbose-field-names
Cela me semble raisonnable.
Cela fonctionnera pour des types de données simples (str, int, float, list, etc.)
>>> def my_print (var_str): print var_str + ':', globals () [var_str] >>> a = 5 >>> b = ['hello', ', world!'] >>> my_print ('a ') a: 5 >>> my_print (' b ') b: [' bonjour ',', monde! ']