¿Convertir el nombre de variable a cadena?

Me gustaría convertir un nombre de variable de python en la cadena equivalente como se muestra. ¿Alguna idea de cómo?

var = {} print ??? # Would like to see 'var' something_else = 3 print ??? # Would print 'something_else' 

Hay un escenario de uso donde puede necesitar esto. No estoy dando a entender que no hay mejores formas o lograr la misma funcionalidad.

Esto sería útil para “volcar” una lista arbitraria de diccionarios en caso de error, en los modos de depuración y otras situaciones similares.

Lo que se necesitaría es el reverso de la función eval() :

 get_indentifier_name_missing_function() 

que tomaría un nombre de identificador (‘variable’, ‘diccionario’, etc.) como argumento, y devolvería una cadena con el nombre del identificador.


Considere el siguiente estado actual de cosas:

 random_function(argument_data) 

Si uno pasa un nombre de identificador (‘función’, ‘variable’, ‘diccionario’, etc.) argument_data a una función random_function() (otro nombre de identificador), uno pasa un identificador (por ejemplo: ) a otro identificador (por ejemplo: ):

 () 

A mi entender, solo la dirección de memoria se pasa a la función:

 () 

Por lo tanto, uno tendría que pasar una cadena como un argumento a random_function() para que esa función tenga el nombre del identificador del argumento:

 random_function('argument_data') 

Dentro de la random_function ()

 def random_function(first_argument): 

, uno usaría la cadena ya provista 'argument_data' para:

  1. sirve como un ‘nombre de identificador’ (para mostrar, registrar, dividir / concat, lo que sea)
  2. alimenta la función eval() para obtener una referencia al identificador real, y por lo tanto, una referencia a los datos reales:

     print("Currently working on", first_argument) some_internal_var = eval(first_argument) print("here comes the data: " + str(some_internal_var)) 

Desafortunadamente, esto no funciona en todos los casos. Solo funciona si random_function() puede resolver la cadena 'argument_data' en un identificador real. Es decir, si el nombre del identificador argument_data está disponible en el espacio de nombres de random_function() .

Esto no siempre es el caso:

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

Los resultados esperados serían:

 Currently working on: argument_data here comes the data: my data 

Debido a argument_data nombre del identificador argument_data no está disponible en el espacio de nombres de random_function() , esto generaría:

 Currently working on argument_data Traceback (most recent call last): File "~/main1.py", line 6, in  some_module1.random_function('argument_data') File "~/some_module1.py", line 4, in random_function some_internal_var = eval(first_argument) File "", line 1, in  NameError: name 'argument_data' is not defined 

Ahora, considere el uso hipotético de un get_indentifier_name_missing_function() que se comportaría como se describe anteriormente.

Aquí hay un código ficticio de 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) ) ###### 

Los resultados esperados serían:

 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. 

Desafortunadamente, get_indentifier_name_missing_function() no vería los nombres de identificadores “originales” ( some_dictionary_ , some_other_dictionary_2 , some_other_dictionary_n ). Solo vería el nombre del identificador a_dictionary_object .

Por lo tanto el resultado real sería más bien:

 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. 

Por lo tanto, el reverso de la función eval() no será tan útil en este caso.


Actualmente, uno tendría que hacer esto:

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

En conclusión:

  • Python solo pasa las direcciones de memoria como argumentos a las funciones.
  • Las cadenas que representan el nombre de un identificador, solo pueden volver a hacer referencia al identificador real mediante la función eval() si el identificador de nombre está disponible en el espacio de nombres actual.
  • Un inverso hipotético de la función eval() , no sería útil en los casos en que el nombre del identificador no sea ‘visto’ directamente por el código que llama. Por ejemplo, dentro de cualquier función llamada.
  • Actualmente hay que pasar a una función:
    1. la cadena que representa el nombre del identificador
    2. el identificador real (dirección de memoria)

Esto se puede lograr pasando la 'string' y la eval('string') a la función llamada al mismo tiempo. Creo que esta es la forma más “general” de resolver este problema huevo-gallina a través de funciones arbitrarias, módulos, espacios de nombres, sin usar soluciones de esquina. El único inconveniente es el uso de la función eval() que puede conducir fácilmente a código no seguro. Se debe tener cuidado de no alimentar la función eval() con casi cualquier cosa, especialmente datos de entrada externa sin filtrar.

Esto no es posible.

En Python, realmente no existe tal cosa como una “variable”. Lo que realmente tiene Python son “nombres” que pueden tener objetos vinculados a ellos. No importa al objeto a qué nombres, si los hay, podría estar vinculado. Puede estar vinculado a docenas de nombres diferentes, o ninguno.

Considera este ejemplo:

 foo = 1 bar = 1 baz = 1 

Ahora, suponga que tiene el objeto entero con el valor 1, y desea trabajar hacia atrás y encontrar su nombre. ¿Qué imprimirías? Tres nombres diferentes tienen ese objeto vinculado a ellos, y todos son igualmente válidos.

En Python, un nombre es una forma de acceder a un objeto, por lo que no hay forma de trabajar con nombres directamente. Puede haber alguna forma inteligente de hackear los códigos de byte de Python o algo para obtener el valor del nombre, pero eso es, en el mejor de los casos, un truco de salón.

Si sabes que quieres print foo para imprimir "foo" , es mejor que ejecutes print "foo" en primer lugar.

EDITAR: He cambiado la redacción ligeramente para hacer esto más claro. Además, aquí hay un ejemplo aún mejor:

 foo = 1 bar = foo baz = foo 

En la práctica, Python reutiliza el mismo objeto para enteros con valores comunes como 0 o 1, por lo que el primer ejemplo debe vincular el mismo objeto a los tres nombres. Pero este ejemplo es muy claro: el mismo objeto está vinculado a foo, bar y baz.

Busqué esta pregunta porque quería que un progtwig de Python imprima sentencias de asignación para algunas de las variables en el progtwig. Por ejemplo, podría imprimir “foo = 3, bar = 21, baz = 432”. La función de impresión necesitaría los nombres de las variables en forma de cadena. Pude haber proporcionado mi código con las cadenas “foo”, “bar” y “baz”, pero me sentía como si me repitiera. Después de leer las respuestas anteriores, desarrollé la solución a continuación.

La función globals () se comporta como un dict con nombres de variables (en forma de cadenas) como teclas. Quería recuperar de globals () la clave correspondiente al valor de cada variable. El método globals (). Items () devuelve una lista de tuplas; en cada tupla el primer elemento es el nombre de la variable (como una cadena) y el segundo es el valor de la variable. Mi función variablename () busca en esa lista para encontrar el nombre de la variable que corresponde al valor de la variable cuyo nombre necesito en forma de cadena.

La función itertools.ifilter () realiza la búsqueda probando cada tupla en la lista globals (). Items () con la función lambda x: var is globals()[x[0]] . En esa función x es la tupla que se está probando; x [0] es el nombre de la variable (como una cadena) y x [1] es el valor. La función lambda comprueba si el valor de la variable probada es el mismo que el valor de la variable pasada a variablename (). De hecho, al usar el operador is , la función lambda comprueba si el nombre de la variable probada está vinculado al mismo objeto exacto que la variable pasada a variablename (). Si es así, la tupla pasa la prueba y es devuelta por ifilter ().

La función itertools.ifilter () en realidad devuelve un iterador que no devuelve ningún resultado hasta que se llama correctamente. Para [tpl[0] for tpl ... globals().items())] correctamente, lo puse dentro de una lista de comprensión [tpl[0] for tpl ... globals().items())] . La lista de comprensión guarda solo el nombre de la variable tpl[0] , ignorando el valor de la variable. La lista que se crea contiene uno o más nombres (como cadenas) que están vinculados al valor de la variable pasada a variablename ().

En los usos de nombre de variable () que se muestran a continuación, la cadena deseada se devuelve como un elemento en una lista. En muchos casos, será el único elemento de la lista. Sin embargo, si a otro nombre de variable se le asigna el mismo valor, la lista será más larga.

 >>> 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'] 

Técnicamente, la información está disponible para usted, pero, como otros han preguntado, ¿cómo la usaría de manera sensata?

 >>> x = 52 >>> globals() {'__builtins__': , '__name__': '__main__', 'x': 52, '__doc__': None, '__package__': None} 

Esto muestra que el nombre de la variable está presente como una cadena en el diccionario globals ().

 >>> globals().keys()[2] 'x' 

En este caso, sucede que es la tercera clave, pero no hay una manera confiable de saber dónde terminará un nombre de variable dado

 >>> for k in globals().keys(): ... if not k.startswith("_"): ... print k ... x >>> 

Podría filtrar las variables del sistema de esta manera, pero aún obtendrá todos sus propios elementos. Simplemente ejecutando el código anterior creó otra variable “k” que cambió la posición de “x” en el dict.

Pero tal vez este sea un comienzo útil para ti. Si nos dice para qué desea esta capacidad, es posible que se proporcione más información útil.

siempre que sea una variable y no una segunda clase, esto aquí funciona para mí:

 def print_var_name(variable): for name in globals(): if eval(name) == variable: print name foo = 123 print_var_name(foo) >>>foo 

esto sucede para los miembros de la clase:

 class xyz: def __init__(self): pass member = xyz() print_var_name(member) >>>member 

Y esto para las clases (como ejemplo):

 abc = xyz print_var_name(abc) >>>abc >>>xyz 

Así que para las clases te da el nombre y las propiedades.

De alguna manera tienes que referirte a la variable de la que deseas imprimir el nombre. Así se vería así:

 print varname(something_else) 

No existe tal función, pero si la hubiera, sería inútil. Tienes que escribir something_else , por lo que también puedes escribir comillas a la izquierda y a la derecha para imprimir el nombre como una cadena:

 print "something_else" 

¿Qué estás intentando lograr? No hay absolutamente ninguna razón para hacer lo que usted describe, y es probable que haya una solución mucho mejor para el problema que está tratando de resolver.

La alternativa más obvia a lo que usted solicita es un diccionario. Por ejemplo:

 >>> my_data = {'var': 'something'} >>> my_data['something_else'] = 'something' >>> print my_data.keys() ['var', 'something_else'] >>> print my_data['var'] something 

Principalmente como un … desafío, implementé tu salida deseada. ¡No uses este código, por favor!

 #!/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 

¿Django no hace esto cuando genera nombres de campo?

http://docs.djangoproject.com/en/dev//topics/db/models/#verbose-field-names

Me parece razonable.

Creo que esta es una solución genial y supongo que lo mejor que puedes conseguir. Pero, ¿ve alguna manera de manejar los resultados ambiguos, su función puede volver? Como el operador “es” se comporta inesperadamente con los números enteros , los enteros bajos y las cadenas del mismo valor se almacenan en la memoria caché de python, de modo que su función de nombre de variable puede proporcionar resultados ambiguos con una alta probabilidad. En mi caso, me gustaría crear un decorador, que agregue una nueva variable a una clase por el nombre varial que la pase:

 def inject(klass, dependency): klass.__dict__["__"+variablename(dependency)]=dependency 

Pero si su método devuelve resultados ambiguos, ¿cómo puedo saber el nombre de la variable que agregué?

 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... 

Tal vez si también verifico la lista local, al menos podría eliminar la “dependencia” -Variable de la lista, pero esto no será un resultado confiable.

Aquí hay una variación sucinta que le permite especificar cualquier directorio. El problema con el uso de directorios para encontrar algo es que múltiples variables pueden tener el mismo valor. Entonces este código devuelve una lista de posibles variables.

 def varname( var, dir=locals()): return [ key for key, val in dir.items() if id( val) == id( var)] 

Esto funcionará para tipos de datos simples (str, int, float, list etc.)

 >>> def my_print (var_str): 
       imprimir var_str + ':', globals () [var_str]
 >>> a = 5
 >>> b = ['hola', ', mundo!']
 >>> my_print ('a')
 a: 5
 >>> my_print ('b')
 b: ['hola', ', mundo!']
 print "var" print "something_else" 

¿O te refieres a algo_else?