Obteniendo el nombre de una variable como una cadena

Este hilo explica cómo obtener el nombre de una función como una cadena en Python: ¿Cómo obtener un nombre de función como una cadena en Python?

¿Cómo puedo hacer lo mismo para una variable? (tenga en cuenta que las variables de Python no tienen el atributo __name__ , al menos en Python 2.7.x )

En otras palabras, si tengo una variable como:

 foo = dict() foo['bar'] = 2 

Estoy buscando una función / atributo, por ejemplo, retrieve_name :

 retrieve_name(foo) 

que devuelve la cadena 'foo'

Actualizar:

Como la gente pregunta por qué quiero hacer esto, aquí hay un ejemplo. Me gustaría crear un DataFrame en Pandas a partir de esta lista , donde los nombres de las columnas están dados por los nombres de los diccionarios reales:

 # List of dictionaries for my DataFrame list_of_dicts = [n_jobs, users, queues, priorities] 

Los únicos objetos en Python que tienen nombres canónicos son módulos, funciones y clases, y por supuesto no hay garantía de que este nombre canónico tenga algún significado en ningún espacio de nombres después de que la función o clase haya sido definida o el módulo haya sido importado. Estos nombres también pueden modificarse después de que se crean los objetos, por lo que no siempre son particularmente confiables.

Lo que quiere hacer no es posible sin caminar recursivamente el árbol de objetos nombrados ; un nombre es una referencia unidireccional a un objeto. Un objeto Python común o de variedad de jardín no contiene referencias a sus nombres. ¡Imagina si cada entero, cada dict, cada lista, cada booleano necesita mantener una lista de cadenas que representan los nombres que se refieren a ella! Sería una pesadilla de implementación, con poco beneficio para el progtwigdor.

Incluso si los valores de las variables no apuntan al nombre, tiene acceso a la lista de cada variable asignada y su valor, por lo que me sorprende que solo una persona sugiriera recorrer allí para buscar su nombre var.

Alguien mencionó en esa respuesta que es posible que tenga que caminar sobre la stack y comprobar los locales y los globales de todos para encontrar a foo , pero si foo está asignado en el ámbito en el que está llamando a esta función retrieve_name , puede usar el current frame inspect para obtener Ustedes todas esas variables locales.

Mi explicación podría ser un poco demasiado amplia (tal vez debería haber usado un “foo” menos palabras), pero he aquí cómo se vería en el código ( tenga en cuenta que si hay más de una variable asignada al mismo valor, obtener ambos nombres de variables ):

 import inspect x,y,z = 1,2,3 def retrieve_name(var): callers_local_vars = inspect.currentframe().f_back.f_locals.items() return [var_name for var_name, var_val in callers_local_vars if var_val is var] print retrieve_name(y) 

Si está llamando a esta función desde otra función, algo como:

 def foo(bar): return retrieve_name(bar) foo(baz) 

Y quieres el baz lugar de la bar , solo necesitarás retroceder un scope. Esto se puede hacer agregando un .f_back adicional en la inicialización de caller_local_vars .

Vea un ejemplo aquí: ideone

No creo que esto sea posible. Considere el siguiente ejemplo:

 >>> a = [] >>> b = a >>> id(a) 140031712435664 >>> id(b) 140031712435664 

Los puntos a y b apuntan al mismo objeto, pero el objeto no puede saber qué variables lo señalan.

En python3, esta función obtendrá el nombre más externo en la stack:

 import inspect def retrieve_name(var): """ Gets the name of var. Does it from the out most frame inner-wards. :param var: variable to get name from. :return: string """ for fi in reversed(inspect.stack()): names = [var_name for var_name, var_val in fi.frame.f_locals.items() if var_val is var] if len(names) > 0: return names[0] 

Es útil en cualquier parte del código. Atraviesa la stack invertida buscando el primer partido.

 def name(**variables): return [x for x in variables] 

Se usa así:

 name(variable=variable) 

Aquí hay un enfoque. No recomendaría esto para nada importante, porque será bastante frágil. Pero puede hacerse.

Cree una función que use el módulo de inspect para encontrar el código fuente que lo llamó. Luego, puede analizar el código fuente para identificar los nombres de las variables que desea recuperar. Por ejemplo, aquí hay una función llamada autodict que toma una lista de variables y devuelve un diccionario que autodict nombres de variables a sus valores. P.ej:

 x = 'foo' y = 'bar' d = autodict(x, y) print d 

Daría:

 {'x': 'foo', 'y': 'bar'} 

Inspeccionar el código fuente en sí es mejor que buscar en locals() o globals() porque este último enfoque no le dice cuáles de las variables son las que desea.

En cualquier caso, aquí está el código:

 def autodict(*args): get_rid_of = ['autodict(', ',', ')', '\n'] calling_code = inspect.getouterframes(inspect.currentframe())[1][4][0] calling_code = calling_code[calling_code.index('autodict'):] for garbage in get_rid_of: calling_code = calling_code.replace(garbage, '') var_names, var_values = calling_code.split(), args dyn_dict = {var_name: var_value for var_name, var_value in zip(var_names, var_values)} return dyn_dict 

La acción ocurre en la línea con inspect.getouterframes , que devuelve la cadena dentro del código que llamó autodict .

El inconveniente obvio de este tipo de magia es que hace suposiciones sobre cómo está estructurado el código fuente. Y, por supuesto, no funcionará en absoluto si se ejecuta dentro del intérprete.

Escribí el paquete de hechicería para hacer este tipo de magia de manera robusta. Puedes escribir:

 from sorcery import dict_of columns = dict_of(n_jobs, users, queues, priorities) 

y pasar eso al constructor del dataframe. Es equivalente a:

 columns = dict(n_jobs=n_jobs, users=users, queues=queues, priorities=priorities) 

En Python, las palabras clave def y class unirán un nombre específico al objeto que definen (función o clase). De manera similar, a los módulos se les da un nombre por el hecho de ser llamados algo específico en el sistema de archivos. En los tres casos, hay una manera obvia de asignar un nombre “canónico” al objeto en cuestión.

Sin embargo, para otros tipos de objetos, tal nombre canónico simplemente puede no existir . Por ejemplo, considere los elementos de una lista. Los elementos de la lista no tienen nombres individuales, y es totalmente posible que la única forma de referirse a ellos en un progtwig sea mediante el uso de índices de lista en la lista que contiene. Si esa lista de objetos se pasara a su función, posiblemente no podría asignar identificadores significativos a los valores.

Python no guarda el nombre en el lado izquierdo de una asignación en el objeto asignado porque:

  1. Requeriría averiguar qué nombre era “canónico” entre múltiples objetos en conflicto,
  2. No tendría sentido para los objetos que nunca se asignan a un nombre de variable explícito,
  3. Sería extremadamente ineficiente,
  4. Literalmente, ningún otro lenguaje en existencia hace eso.

Así, por ejemplo, las funciones definidas usando lambda siempre tendrán el “nombre” , en lugar de un nombre de función específico.

El mejor enfoque sería simplemente pedirle a la persona que llama que pase una lista de nombres (opcional). Si escribir el '...','...' es demasiado engorroso, podría aceptar, por ejemplo, una sola cadena que contenga una lista de nombres separados por comas (como hace namedtuple ).

Creo que es tan difícil hacer esto en Python debido al simple hecho de que nunca sabrás el nombre de la variable que estás usando. Entonces, en su ejemplo, podrías hacer:

En lugar de:

 list_of_dicts = [n_jobs, users, queues, priorities] dict_of_dicts = {"n_jobs" : n_jobs, "users" : users, "queues" : queues, "priorities" : priorities} 
 >>> locals()['foo'] {} >>> globals()['foo'] {} 

Si desea escribir su propia función, se podría hacer de tal manera que pueda verificar una variable definida en los locales y luego verificar los globales. Si no encuentra nada, puede comparar en id () para ver si la variable apunta a la misma ubicación en la memoria.

Si su variable está en una clase, podría usar className. dict .keys () o vars (self) para ver si su variable ha sido definida.

Esta función imprimirá el nombre de la variable con su valor:

 def print_this(var): callers_local_vars = inspect.currentframe().f_back.f_locals.items() print(str([k for k, v in callers_local_vars if v is var][0])+': '+str(var)) 
 ***Input & Function call:*** my_var = 10 print_this(my_var) ***Output**:* my_var: 10 

Para las constantes, puede utilizar una enumeración, que permite recuperar su nombre.

Intento obtener el nombre de los locales de inspección, pero no puede procesar var likes a [1], b.val. Después de eso, obtuve una nueva idea: obtener el nombre var del código, ¡y lo bash con éxito! código como el siguiente:

 #direct get from called function code def retrieve_name_ex(var): stacks = inspect.stack() try: func = stacks[0].function code = stacks[1].code_context[0] s = code.index(func) s = code.index("(", s + len(func)) + 1 e = code.index(")", s) return code[s:e].strip() except: return "" 

Si el objective es ayudarlo a realizar un seguimiento de sus variables, puede escribir una función simple que etiquete la variable y devuelva su valor y tipo. Por ejemplo, supongamos que i_f = 3.01 y lo redondeas a un entero llamado i_n para usar en un código, y luego necesitas una cadena i_s que entrará en un informe.

 def whatis(string, x): print(string+' value=',repr(x),type(x)) return string+' value='+repr(x)+repr(type(x)) i_f=3.01 i_n=int(i_f) i_s=str(i_n) i_l=[i_f, i_n, i_s] i_u=(i_f, i_n, i_s) ## make report that identifies all types report='\n'+20*'#'+'\nThis is the report:\n' report+= whatis('i_f ',i_f)+'\n' report+=whatis('i_n ',i_n)+'\n' report+=whatis('i_s ',i_s)+'\n' report+=whatis('i_l ',i_l)+'\n' report+=whatis('i_u ',i_u)+'\n' print(report) 

Esto se imprime en la ventana en cada llamada para fines de depuración y también produce una cadena para el informe escrito. El único inconveniente es que tiene que escribir la variable dos veces cada vez que llama a la función.

Soy un novato de Python y encontré esta manera muy útil de registrar mis esfuerzos mientras programo e bash hacer frente a todos los objetos en Python. Una falla es que whatis () falla si llama a una función descrita fuera del procedimiento donde se usa. Por ejemplo, int (i_f) era una llamada de función válida solo porque Python conoce la función int . Puede llamar a whatis () usando int (i_f ** 2), pero si por alguna extraña razón usted elige definir una función llamada int_squared, debe declararse dentro del procedimiento donde se usa whatis ().

Solo otra forma de hacer esto basado en el contenido de la variable de entrada:

(devuelve el nombre de la primera variable que coincide con la variable de entrada, de lo contrario, Ninguna. Se puede modificar para obtener todos los nombres de variables que tengan el mismo contenido que la variable de entrada)

 def retrieve_name(x, Vars=vars()): for k in Vars: if type(x) == type(Vars[k]): if x is Vars[k]: return k return None