sentencias - str en python
¿Una forma más sencilla de crear un diccionario de variables separadas? (25)
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}
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, esto 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: 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 print eval("''" + str(id(jj)) + "''") print dir()
166707048 [''__builtins__'', ''__doc__'', ''__file__'', ''__name__'', ''__package__'', ''jj'']
Así que hay ''jj'' al final de la lista.
Reescribe el código como:
jj = 123 print eval("''" + str(id(jj)) + "''") for x in dir(): print id(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 nombres está tu variable / object / wypci.
QED.
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}
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
múltiples 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 ámbito 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 complemento, 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.
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''
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]}
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 realizar 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 <type ''dict''>
details(mydic[''first''])
The Value of mydic[''first''] is (0, 1, 2, 3, 4, 5, 6)]
The data type of mydic[''first''] is <type ''list''>
details(mydic.keys())
The Value of mydic.keys() is [''second'', ''third'', ''first'']
The data type of mydic.keys() is <type ''tuple''>
details(mydic[''second''][0])
The Value of mydic[''second''][0] is a
The data type of mydic[''second''][0] is <type ''str''>
No estoy seguro de si puse esto en el lugar correcto, pero pensé que podría ayudar. Espero que lo haga.
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
En python3, esta función obtendrá el nombre más externo en la pila:
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 pila invertida buscando el primer partido.
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}
Escribí el paquete de sorcery para hacer este tipo de magia de manera robusta. Puedes escribir:
from sorcery import dict_of
my_dict = dict_of(foo, bar)
Escribí una pequeña y útil función basada en la respuesta a esta pregunta. Lo pongo aquí en caso de que sea ú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
>>|
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 puede 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 eso 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, aparecería "item" 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 []
''''''
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.
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]
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)
Python3. Use inspeccionar para capturar el espacio de nombres local de 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
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"
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.
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''
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]
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)]
>>> 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''.
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)