¿Una forma más sencilla de crear un diccionario de variables separadas?

Me gustaría poder obtener el nombre de una variable como una cadena, pero no sé si Python tiene tantas capacidades de introspección. Algo como:

>>> print(my_var.__name__) 'my_var' 

Quiero hacer eso porque tengo un montón de vars que me gustaría convertir en un diccionario como:

 bar = True foo = False >>> my_dict = dict(bar=bar, foo=foo) >>> print my_dict {'foo': False, 'bar': True} 

Pero me gustaría algo más automático que eso.

Python tiene locals() y vars() , así que supongo que hay una manera.

¿Estás tratando de hacer esto?

 dict( (name,eval(name)) for name in ['some','list','of','vars'] ) 

Ejemplo

 >>> some= 1 >>> list= 2 >>> of= 3 >>> vars= 4 >>> dict( (name,eval(name)) for name in ['some','list','of','vars'] ) {'list': 2, 'some': 1, 'vars': 4, 'of': 3} 

Como dijo el desvío, esto no es realmente algo que se hace en Python: las variables son asignaciones de nombre a objetos.

Sin embargo , aquí hay una manera de intentarlo:

  >>> a = 1 >>> for k, v in list(locals().iteritems()): if v is a: a_as_str = k >>> a_as_str a >>> type(a_as_str) 'str' 

He querido hacer esto bastante. Este truco es muy similar a la sugerencia de rlotun, pero es de una sola línea, lo que es importante para mí:

 blah = 1 blah_name = [ k for k,v in locals().iteritems() if v is blah][0] 

Python 3+

 blah = 1 blah_name = [ k for k,v in locals().items() if v is blah][0] 

Esto es un hack. No funcionará en todas las distribuciones de implementaciones de Python (en particular, aquellas que no tienen traceback.extract_stack ).

 import traceback def make_dict(*expr): (filename,line_number,function_name,text)=traceback.extract_stack()[-2] begin=text.find('make_dict(')+len('make_dict(') end=text.find(')',begin) text=[name.strip() for name in text[begin:end].split(',')] return dict(zip(text,expr)) bar=True foo=False print(make_dict(bar,foo)) # {'foo': False, 'bar': True} 

Tenga en cuenta que este truco es frágil:

 make_dict(bar, foo) 

(Llamar a make_dict en 2 líneas) no funcionará.

En lugar de tratar de generar el dictado de los valores foo y bar , sería mucho más Pythonic generar el dictado de los nombres de variable de cadena 'foo' y 'bar' :

 dict([(name,locals()[name]) for name in ('foo','bar')]) 

Esto no es posible en Python, que realmente no tiene “variables”. Python tiene nombres, y puede haber más de un nombre para el mismo objeto.

Creo que mi problema ayudará a ilustrar por qué esta pregunta es útil, y puede dar un poco más de información sobre cómo responderla. Escribí una pequeña función para hacer una comprobación rápida en línea de varias variables en mi código. Básicamente, enumera el nombre de la variable, el tipo de datos, el tamaño y otros atributos, por lo que puedo detectar rápidamente cualquier error que haya cometido. El código es simple:

 def details(val): vn = val.__name__ # If such a thing existed vs = str(val) print("The Value of "+ str(vn) + " is " + vs) print("The data type of " + vn + " is " + str(type(val))) 

Por lo tanto, si tiene una situación complicada de diccionario / lista / tupla, sería muy útil que el intérprete devuelva el nombre de la variable que asignó. Por ejemplo, aquí hay un diccionario extraño:

 m = 'abracadabra' mm=[] for n in m: mm.append(n) mydic = {'first':(0,1,2,3,4,5,6),'second':mm,'third':np.arange(0.,10)} details(mydic) The Value of mydic is {'second': ['a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a'], 'third': array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]), 'first': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]} The data type of mydic is  details(mydic['first']) The Value of mydic['first'] is (0, 1, 2, 3, 4, 5, 6)] The data type of mydic['first'] is  details(mydic.keys()) The Value of mydic.keys() is ['second', 'third', 'first'] The data type of mydic.keys() is  details(mydic['second'][0]) The Value of mydic['second'][0] is a The data type of mydic['second'][0] is  

No estoy seguro de si puse esto en el lugar correcto, pero pensé que podría ayudar. Espero que lo haga.

Escribí una pequeña y útil función basada en la respuesta a esta pregunta. Lo pongo aquí por si es útil.

 def what(obj, callingLocals=locals()): """ quick function to print name of input and value. If not for the default-Valued callingLocals, the function would always get the name as "obj", which is not what I want. """ for k, v in list(callingLocals.items()): if v is obj: name = k print(name, "=", obj) 

uso:

 >> a = 4 >> what(a) a = 4 >>| 

Encuentro que si ya tiene una lista específica de valores, de la manera descrita por @S. Lotts es el mejor; sin embargo, la forma descrita a continuación funciona bien para obtener todas las variables y clases agregadas a lo largo del código SIN la necesidad de proporcionar el nombre de la variable, aunque puede especificarlas si lo desea. El código puede ser extendido para excluir Clases.

 import types import math # mainly showing that you could import what you will before d # Everything after this counts d = dict(globals()) def kv_test(k,v): return (k not in d and k not in ['d','args'] and type(v) is not types.FunctionType) def magic_print(*args): if len(args) == 0: return {k:v for k,v in globals().iteritems() if kv_test(k,v)} else: return {k:v for k,v in magic_print().iteritems() if k in args} if __name__ == '__main__': foo = 1 bar = 2 baz = 3 print magic_print() print magic_print('foo') print magic_print('foo','bar') 

Salida:

 {'baz': 3, 'foo': 1, 'bar': 2} {'foo': 1} {'foo': 1, 'bar': 2} 

En Python 3 esto es fácil.

 myVariable = 5 for v in locals(): if id(v) == id("myVariable"): print(v, locals()[v]) 

esto imprimirá:

myVariable 5

Python3. Use inspeccionar para capturar el espacio de nombres local de la llamada y luego use las ideas presentadas aquí. Puede devolver más de una respuesta como se ha señalado.

 def varname(var): import inspect frame = inspect.currentframe() var_id = id(var) for name in frame.f_back.f_locals.keys(): try: if id(eval(name)) == var_id: return(name) except: pass 

Aquí está la función que creé para leer los nombres de las variables. Es más general y puede ser utilizado en diferentes aplicaciones:

 def get_variable_name(*variable): '''gets string of variable name inputs variable (str) returns string ''' if len(variable) != 1: raise Exception('len of variables inputed must be 1') try: return [k for k, v in locals().items() if v is variable[0]][0] except: return [k for k, v in globals().items() if v is variable[0]][0] 

Para usarlo en la pregunta especificada:

 >>> foo = False >>> bar = True >>> my_dict = {get_variable_name(foo):foo, get_variable_name(bar):bar} >>> my_dict {'bar': True, 'foo': False} 

Al leer el hilo, vi una gran cantidad de fricción. Es bastante fácil dar una mala respuesta, luego dejar que alguien dé la respuesta correcta. De todos modos, aquí es lo que encontré.

De: [effbot.org] ( http://effbot.org/zone/python-objects.htm#names )

Los nombres son un poco diferentes: no son realmente propiedades del objeto, y el objeto en sí mismo no sabe cómo se llama.

Un objeto puede tener cualquier número de nombres, o ningún nombre en absoluto.

Los nombres se encuentran en espacios de nombres (como un espacio de nombres de módulo, un espacio de nombres de instancia, un espacio de nombres local de una función).

Nota: que dice que el objeto en sí no sabe cómo se llama , así que esa fue la clave. Los objetos de Python no son autorreferenciales. Luego dice: Los nombres viven en los espacios de nombres . Tenemos esto en TCL / TK. Entonces tal vez mi respuesta ayude (pero me ayudó)


     jj = 123
     imprimir eval ("'" + str (id (jj)) + "'")
     imprimir dir ()

 166707048
 ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'jj']

Así que hay ‘jj’ al final de la lista.

Reescribe el código como:


     jj = 123
     imprimir eval ("'" + str (id (jj)) + "'")
     para x en dir ():
         ID de impresión (eval (x))

 161922920
 ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'jj']
 3077447796
 136515736
 3077408320
 3077656800
 136515736
 161922920

Este bit desagradable de ID de código es el nombre de variable / object / whatever-you-pedantics-call-it.

Entonces, ahí está. La dirección de memoria de ‘jj’ es la misma cuando la buscamos directamente, como cuando buscamos el diccionario en el espacio de nombres global. Estoy seguro de que puedes hacer una función para hacer esto. Solo recuerda en qué espacio de nombre está tu variable / object / wypci.

QED.

 import re import traceback pattren = re.compile(r'[\W+\w+]*get_variable_name\((\w+)\)') def get_variable_name(x): return pattren.match( traceback.extract_stack(limit=2)[0][3]) .group(1) a = 1 b = a c = b print get_variable_name(a) print get_variable_name(b) print get_variable_name(c) 

Subí una solución a pypi . Es un módulo que define un equivalente de la función nameof de C #.

Se itera a través de las instrucciones de bytecode para el cuadro al que se llama, obteniendo los nombres de las variables / atributos que se le pasan. Los nombres se encuentran en el .argrepr de las instrucciones de LOAD que siguen al nombre de la función.

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

 from sorcery import dict_of my_dict = dict_of(foo, bar) 

La mayoría de los objetos no tienen un atributo __name__ . (Las clases, funciones y módulos sí; ¿hay más tipos incorporados que tengan uno?)

¿Qué otra cosa esperaría para una print(my_var.__name__) distinta de print("my_var") ? ¿Puedes simplemente usar la cuerda directamente?

Usted podría “cortar” un dict:

 def dict_slice(D, keys, default=None): return dict((k, D.get(k, default)) for k in keys) print dict_slice(locals(), ["foo", "bar"]) # or use set literal syntax if you have a recent enough version: print dict_slice(locals(), {"foo", "bar"}) 

Alternativamente:

 throw = object() # sentinel def dict_slice(D, keys, default=throw): def get(k): v = D.get(k, throw) if v is not throw: return v if default is throw: raise KeyError(k) return default return dict((k, get(k)) for k in keys) 

Bueno, encontré la misma necesidad hace unos días y tuve que obtener el nombre de una variable que apuntaba al objeto en sí.

¿Y por qué era tan necesario?

En resumen, estaba construyendo un plug-in para Maya . El complemento del núcleo se creó con C ++ pero la GUI se dibuja a través de Python (ya que no requiere un uso intensivo del procesador). Como todavía no sé cómo return varios valores desde el complemento, excepto el MStatus predeterminado, por lo tanto, para actualizar un diccionario en Python tuve que pasar el nombre de la variable, apuntando al objeto que implementa la GUI y que contenía el diccionario, al complemento y luego usa MGlobal::executePythonCommand() para actualizar el diccionario desde el scope global de Maya .

Para hacer eso lo que hice fue algo como:

 import time class foo(bar): def __init__(self): super(foo, self).__init__() self.time = time.time() #almost guaranteed to be unique on a single computer def name(self): g = globals() for x in g: if isinstance(g[x], type(self)): if g[x].time == self.time: return x #or you could: #return filter(None,[x if g[x].time == self.time else None for x in g if isinstance(g[x], type(self))]) #and return all keys pointing to object itself 

Sé que no es la solución perfecta, ya que muchas claves podrían estar apuntando al mismo objeto, por ejemplo:

 a = foo() b = a b.name() >>>b or >>>a 

y que el enfoque no es seguro para subprocesos. Corrígeme si estoy equivocado.

Al menos, este enfoque resolvió mi problema al obtener el nombre de cualquier variable en el ámbito global que apuntaba al objeto en sí y lo pasaba al plug-in, como argumento, para su uso interno.

Intenté esto en int (la clase entera primitiva) pero el problema es que estas clases primitivas no se pasan por alto (por favor, corrija la terminología técnica utilizada si es incorrecta). Podrías volver a implementar int y luego hacer int = foo pero a = 3 nunca será un objeto de foo sino de primitivo. Para superar eso, tienes que a a = foo(3) para que a.name() funcione.

Con Python 2.7 y más reciente también hay una comprensión del diccionario que lo hace un poco más corto. Si es posible, usaría getattr en lugar de eval (eval is evil) como en la respuesta superior. El yo puede ser cualquier objeto que tenga el contexto que está mirando. Puede ser un objeto o locals = locals () etc.

 {name: getattr(self, name) for name in ['some', 'vars', 'here]} 

Tal vez estoy pensando demasiado en esto, pero …

 str_l = next((k for k,v in locals().items() if id(l) == id(v))) >>> bar = True >>> foo = False >>> my_dict=dict(bar=bar, foo=foo) >>> next((k for k,v in locals().items() if id(bar) == id(v))) 'bar' >>> next((k for k,v in locals().items() if id(foo) == id(v))) 'foo' >>> next((k for k,v in locals().items() if id(my_dict) == id(v))) 'my_dict' 

Estaba trabajando en un problema similar. @ S.Lott dijo: “Si tiene la lista de variables, ¿para qué sirve” descubrir “sus nombres?” Y mi respuesta es solo para ver si se podría hacer y si, por alguna razón, desea clasificar sus variables por tipo en listas. De todos modos, en mi investigación encontré este hilo y mi solución está un poco expandida y se basa en la solución @rlotun. Otra cosa, @unutbu dijo: “Esta idea tiene mérito, pero tenga en cuenta que si dos nombres de variables hacen referencia al mismo valor (por ejemplo, Verdadero), entonces se puede devolver un nombre de variable no deseado”. En este ejercicio fue cierto, así que lo isClass = [i for i in isClass if i != 'item'] utilizando una lista de comprensión similar a esta para cada posibilidad: isClass = [i for i in isClass if i != 'item'] . Sin él, “item” aparecería en cada lista.

 __metaclass__ = type from types import * class Class_1: pass class Class_2: pass list_1 = [1, 2, 3] list_2 = ['dog', 'cat', 'bird'] tuple_1 = ('one', 'two', 'three') tuple_2 = (1000, 2000, 3000) dict_1 = {'one': 1, 'two': 2, 'three': 3} dict_2 = {'dog': 'collie', 'cat': 'calico', 'bird': 'robin'} x = 23 y = 29 pie = 3.14159 eee = 2.71828 house = 'single story' cabin = 'cozy' isClass = []; isList = []; isTuple = []; isDict = []; isInt = []; isFloat = []; isString = []; other = [] mixedDataTypes = [Class_1, list_1, tuple_1, dict_1, x, pie, house, Class_2, list_2, tuple_2, dict_2, y, eee, cabin] print '\nMIXED_DATA_TYPES total count:', len(mixedDataTypes) for item in mixedDataTypes: try: # if isinstance(item, ClassType): # use this for old class types (before 3.0) if isinstance(item, type): for k, v in list(locals().iteritems()): if v is item: mapping_as_str = k isClass.append(mapping_as_str) isClass = [i for i in isClass if i != 'item'] elif isinstance(item, ListType): for k, v in list(locals().iteritems()): if v is item: mapping_as_str = k isList.append(mapping_as_str) isList = [i for i in isList if i != 'item'] elif isinstance(item, TupleType): for k, v in list(locals().iteritems()): if v is item: mapping_as_str = k isTuple.append(mapping_as_str) isTuple = [i for i in isTuple if i != 'item'] elif isinstance(item, DictType): for k, v in list(locals().iteritems()): if v is item: mapping_as_str = k isDict.append(mapping_as_str) isDict = [i for i in isDict if i != 'item'] elif isinstance(item, IntType): for k, v in list(locals().iteritems()): if v is item: mapping_as_str = k isInt.append(mapping_as_str) isInt = [i for i in isInt if i != 'item'] elif isinstance(item, FloatType): for k, v in list(locals().iteritems()): if v is item: mapping_as_str = k isFloat.append(mapping_as_str) isFloat = [i for i in isFloat if i != 'item'] elif isinstance(item, StringType): for k, v in list(locals().iteritems()): if v is item: mapping_as_str = k isString.append(mapping_as_str) isString = [i for i in isString if i != 'item'] else: for k, v in list(locals().iteritems()): if v is item: mapping_as_str = k other.append(mapping_as_str) other = [i for i in other if i != 'item'] except (TypeError, AttributeError), e: print e print '\n isClass:', len(isClass), isClass print ' isList:', len(isList), isList print ' isTuple:', len(isTuple), isTuple print ' isDict:', len(isDict), isDict print ' isInt:', len(isInt), isInt print ' isFloat:', len(isFloat), isFloat print 'isString:', len(isString), isString print ' other:', len(other), other # my output and the output I wanted ''' MIXED_DATA_TYPES total count: 14 isClass: 2 ['Class_1', 'Class_2'] isList: 2 ['list_1', 'list_2'] isTuple: 2 ['tuple_1', 'tuple_2'] isDict: 2 ['dict_1', 'dict_2'] isInt: 2 ['x', 'y'] isFloat: 2 ['pie', 'eee'] isString: 2 ['house', 'cabin'] other: 0 [] ''' 

puedes usar easydict

 >>> from easydict import EasyDict as edict >>> d = edict({'foo':3, 'bar':{'x':1, 'y':2}}) >>> d.foo 3 >>> d.bar.x 1 >>> d = edict(foo=3) >>> d.foo 3 

otro ejemplo:

 >>> d = EasyDict(log=False) >>> d.debug = True >>> d.items() [('debug', True), ('log', False)] 

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.

Si bien esta es probablemente una idea horrible, sigue las mismas líneas que la respuesta de rlotun pero devolverá el resultado correcto más a menudo.

 import inspect def getVarName(getvar): frame = inspect.currentframe() callerLocals = frame.f_back.f_locals for k, v in list(callerLocals.items()): if v is getvar(): callerLocals.pop(k) try: getvar() callerLocals[k] = v except NameError: callerLocals[k] = v del frame return k del frame 

Lo llamas así:

 bar = True foo = False bean = False fooName = getVarName(lambda: foo) print(fooName) # prints "foo" 

debe obtener la lista y luego volver

 def get_var_name(**kwargs): """get variable name get_var_name(var = var) Returns: [str] -- var name """ return list(kwargs.keys())[0] 
 >>> a = 1 >>> b = 1 >>> id(a) 34120408 >>> id(b) 34120408 >>> a is b True >>> id(a) == id(b) True 

de esta manera obtener varname para tal vez ‘a’ o ‘b’.