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


220

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

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

Quiero hacer eso porque tengo un montón de variables 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.


31
Como la gente parece estar confundida acerca de lo que se pide, lo volveré a expresar aquí porque es una pregunta interesante. Dado un conjunto [foo, bar, baz], desea un diccionario como {'foo': foo, 'bar': bar, 'baz': baz} y no sabe qué variables hay en el conjunto. entonces el interlocutor pregunta cómo se obtiene el nombre de una variable como una cadena en python. Ahora, con suerte, las personas pueden navegar a través de las horribles respuestas para encontrar los pocos lugares donde se aprende por qué esto no es realmente una buena idea en Python.
Jesse Sherlock


2
Un uso para la técnica sería racionalizar las llamadas de formato de cadena: '{var} {foo} {bar}'. Format (** named (var, foo, bar)), donde "named" es la función que devuelve el dict ( 'var': var) como se describe.
Gordon Bean

44
Creo que esta es realmente una mala pregunta porque los nombres están asignados a objetos, puede tener varios nombres apuntando al mismo objeto, y nunca he visto la necesidad de lograr el objetivo de invertir ese mapeo. Por lo tanto, el hecho de que la respuesta incorrecta se acepte aquí no tiene sentido: si una búsqueda en Google lo trajo aquí, claramente está haciendo la pregunta incorrecta.
Aaron Hall

1
¡Esta es una gran idea para depurar!
John ktejik

Respuestas:


48

¿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}

1
rlotun está más cerca del "espíritu" inicial ya que permite descubrir el nombre. Podría usar tanto tu respuesta. O tal vez solo use mi maldita mano para escribir. Algunas cosas simplemente no están hechas para ser tan automatizadas ...
e-satis

77
@ e-satis: Para que @ rlotun funcione, debe proporcionar la lista de variables. Si tiene la lista de variables, ¿cuál es el punto de "descubrir" sus nombres?
S.Lott

44
¿Por qué evaluar en lugar de usar explícitamente locales y globales?

1
@Roger Pate: Porque no podía entender cuál era el punto de todo el ejercicio.
S.Lott

242
Esta respuesta no responde la pregunta formulada. Si tiene la lista de variables, ¿cuál es el punto de "descubrir" sus nombres? Para evitar la duplicación de modo que en lugar de print('x: ' + x)uno pueda escribir magic_print(x)y tener la misma salida sin escribir el nombre de la variable dos veces.
Piotr Dobrogost

130

Como dijimos, esto no es realmente algo que se hace en Python: las variables son en realidad asignaciones de nombres a objetos.

Sin embargo , aquí hay una forma 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'

14
Esta idea tiene mérito, pero tenga en cuenta que si dos nombres de variables hacen referencia al mismo valor (por ejemplo True), podría devolverse un nombre de variable no deseado.
unutbu

14
¿Por qué en id(v) == id(a)lugar de v is a? Esto fallará para los objetos vinculados a múltiples variables, como ints, cadenas y cualquier tipo definido por el usuario implementado de manera similar.

Sí, v is asería una mejor opción. ¡Y sí, ciertamente peligroso, dadas todas las trampas potenciales que podrían surgir! ;-)
rlotun

16
@ e-satis Me sorprende que no hayas marcado esta respuesta como la respuesta, ya que estoy de acuerdo con tu comentario diciendo que rlotun está más cerca del "espíritu" inicial ya que permite descubrir el nombre . Además, la respuesta de S.Lott no responde a su pregunta en absoluto ...
Piotr Dobrogost

2
"excesivo y peligroso" ... y el uso de eval no lo es?
error

63

He querido hacer esto bastante. Este truco es muy similar a la sugerencia de rlotun, pero es una frase, lo cual 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]

3
@keflavich Me gustó mucho este enfoque y lo he usado de vez en cuando. Sin embargo, no puedo hacer que funcione dentro de las funciones. Supongo que hay formas "mejores" de hacerlo, pero ninguna es tan agradable y sencilla como dice nbubis. ¿Has podido usarlo en las funciones keflavich? Aquí es donde hago una pregunta sobre esto.
Leo

10
Tenga en cuenta que en Python 3, iteritems()se reemplaza poritems()
Jonathan Wheeler

Esto no es confiable: spam = 1; blah = 1; blah_name = [ k for k,v in locals().items() if v is blah][0]; print(blah_name)Salidasspam
andreasdr

1
@andreasdr eso es porque spam = 1, blah = 1; assert spam is blah. La solución se rompe al comparar tipos de datos primitivos.
JYun

17

Este es un truco. 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)

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

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

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

1
+1 para el truco inteligente. Por supuesto, el rastreo es muy lento, por lo que puede ser lento usarlo.
e-satis

1
+1111111 !!!! Sí, es lento, pero cuando se usa para reemplazar a print("a_very_long_name: {}'.format(a_very_long_name))quién le importa.
viernes

14

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.


Sí, lo sé, hice la pregunta simple, pero esperaba algo más como "get_var_tags (var) [0]".
e-satis

10

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 verificación rápida de la cabeza en línea en varias variables en mi código. Básicamente, enumera el nombre de la variable, el tipo de datos, el tamaño y otros atributos, para que pueda 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)))

Entonces, si tiene una situación complicada de diccionario / lista / tupla, sería muy útil que el intérprete le 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 si puse esto en el lugar correcto, pero pensé que podría ayudar. Espero que si.


Entonces, con su verificación de la cabeza, ¿tiene en cuenta el hecho de que las variables / nombres pueden estar apuntando a diferentes cosas en diferentes momentos en el código? Por ejemplo, ¿ myconnectionpodría apuntar a un valor booleano en un punto, un número entero en otro momento y una conexión de socket en otro punto en la ejecución del código?

9

Escribí una función útil poco útil 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
>>|

6

Me parece que si ya tiene una lista específica de valores, esa es la forma 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 en todo el código SIN la necesidad de proporcionar el nombre de la variable, aunque puede especificarlas si lo desea. El código se puede extender 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}

6

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


Esto es similar al enfoque de rlotun pero un poco más simple
officialhopsof

10
-1. Abra una nueva ventana de intérprete e intente for v in locals().
Aire

No estoy totalmente seguro de lo que quieres decir?
officialhopsof

44
Esto dará un error: RuntimeError: el diccionario cambió de tamaño durante la iteración ...
Nizar B.

2
como sea que puedas hacerlofor v in list(locals()):
Phylliida

5

Python3. Use inspeccionar para capturar el espacio de nombres local que llama 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

Buena respuesta, pero para mí es mejor con: ... id (eval (name, None, frame.f_back.f_locals)) == ...
Emmanuel DUMAS

5

Aquí está la función que creé para leer los nombres de las variables. Es más general y se puede usar 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}

4

Al leer el hilo, vi mucha fricción. Es bastante fácil dar una mala respuesta y 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: en realidad no son propiedades del objeto, y el objeto en sí no sabe cómo se llama.

Un objeto puede tener cualquier cantidad de nombres, o ningún nombre.

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

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

    jj = 123
    print eval ("'" + str (id (jj)) + "'")
    dir de impresión ()

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

Entonces hay 'jj' al final de la lista.

Reescribe el código como:

    jj = 123
    print 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 desagradable código de identificación de código se llama 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 nombre global. Estoy seguro de que puedes hacer una función para hacer esto. Solo recuerde en qué espacio de nombres se encuentra su variable / objeto / wypci.

QED


66
Tienes dos usos locos de eval aquí. La primera es exactamente el mismo que: print id(jj). El segundo simplemente busca el nombre y se puede hacer más fácilmente vars().
Ned Batchelder

2

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'

¡Excelente! Esto es lo que estaba buscando. Gracias @ rh0dium ... \ nvariable = 1 \n [k for k,v in locals().items() if id(variable) == id(v)] \n Out[14]: ['variable']
Majdi

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

2

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

Se itera a través de instrucciones de código de bytes para el marco al que se llama, obteniendo los nombres de variables / atributos que se le pasan. Los nombres se encuentran en el .argreprde LOADinstrucciones siguiente nombre de la función.


2

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

from sorcery import dict_of

my_dict = dict_of(foo, bar)

1

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é más esperarías para que print(my_var.__name__)no sea print("my_var")? ¿Puedes simplemente usar la cadena directamente?

Podrías "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)

2
+1 pero sé que ese nombre no existe, ¿por qué todos toman este "algo así" literalmente? Su solución no resuelve el problema ya que no quiero codificar el nombre, de lo contrario, haría la solución dict que ya di en la pregunta.
e-satis

3
@ e-satis: Si simplemente usar todo en locales () resuelve su problema, no tengo idea de lo que está preguntando. Supongo que estás de acuerdo con las llamadas some_func(var), así que traté de señalar que no está muy lejos some_func("var"), con dictslice que te permite obtener la asignación de nombre-valor para múltiples variables a la vez.

1

Bueno, hace unos días me encontré con la misma necesidad 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 complemento para Maya . El complemento central se creó con C ++, pero la GUI se dibuja a través de Python (ya que no requiere un procesador intensivo). Como todavía no sé cómo hacer returnmúltiples valores desde el complemento, excepto el predeterminado MStatus, por lo tanto, para actualizar un diccionario en Python, tuve que pasar el nombre de la variable, señalando el objeto que implementa la GUI y cuál contenía el diccionario en sí, para el complemento y luego usa MGlobal::executePythonCommand()para actualizar el diccionario desde el alcance 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 globalsmuchas de las teclas 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 apuntara al objeto en sí mismo y pasarlo al complemento, como argumento, para su uso interno.

Probé esto en int(la clase entera primitiva) pero el problema es que estas clases primitivas no se omiten (corrija la terminología técnica utilizada si es incorrecta). Puede volver a implementar inty luego hacerint = foo pero a = 3nunca serás objeto de foosino de lo primitivo. Para superar eso tienes a = foo(3)que ponerte a.name()a trabajar.


1

Con Python 2.7 y versiones posteriores también hay comprensión del diccionario, lo que lo hace un poco más corto. Si fuera posible, usaría getattr en su lugar eval (eval es malvado) como en la respuesta superior. Self puede ser cualquier objeto que tenga el contexto que estás mirando. Puede ser un objeto o locales = locales () etc.

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

1

Estaba trabajando en un problema similar. @ S.Lott dijo "Si tienes la lista de variables, ¿cuál es el punto de" descubrir "sus nombres?" Y mi respuesta es solo para ver si se puede hacer y si por alguna razón desea ordenar sus variables por tipo en listas. De todos modos, en mi investigación me encontré con este hilo y mi solución se amplió un poco y se basa en la solución @rlotun. Otra cosa, dijo @unutbu, "esta idea tiene mérito, pero tenga en cuenta que si dos nombres de variables hacen referencia al mismo valor (por ejemplo, True), podría devolverse un nombre de variable no deseado". En este ejercicio que era verdad lo que se ocuparon de ello mediante el uso de una lista por comprensión similar a esto para cada posibilidad: isClass = [i for i in isClass if i != 'item']. Sin él, el "elemento" 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 []
'''

El problema que tomaría con esto es que los nombres no son propiedades de los objetos. Un solo objeto puede tener múltiples nombres o ningún nombre. Por ejemplo, si agregó pi = piea su código, obtendría una entrada adicional en su isFloatlista. Si agregó tuple_1[0]a su mixedDataTypeslista, no se encontrará ningún nombre para él a pesar de que "uno" esté en su código dos veces (aunque gracias a la secuencia interna, ambos serán referencias al mismo objeto).
Blckknght

1
@Blckknght --- Estoy de acuerdo. Esta es solo otra forma de hacer algo que realmente no estaba destinado a hacerse. No dije que ofrezca resultados únicos o que sea infalible. Al hacer esto descubrí que usar piy ecomo variables causaba resultados no deseados y eso es porque ambos son parte de la mathbiblioteca. Para mí esto fue solo un ejercicio para ver si se podía hacer a pesar de que el resultado final no es perfecto. En mi aprendizaje de este idioma, leer libros solo llega hasta cierto punto. En mi opinión, si realmente quieres aprender el idioma, tienes que jugar "qué pasaría si" y ver qué se te ocurre.
Michael Swartz

1

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

1

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.


0

Si bien esta es probablemente una idea horrible, está en la misma línea que la respuesta de rlotun, pero devolverá el resultado correcto con mayor frecuencia.

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"

0

debería obtener la lista y luego regresar

def get_var_name(**kwargs):
    """get variable name
        get_var_name(var = var)
    Returns:
        [str] -- var name
    """
    return list(kwargs.keys())[0]

0

No devolverá el nombre de la variable, pero puede crear fácilmente un diccionario a partir de una variable global.

class CustomDict(dict):
    def __add__(self, other):
        return CustomDict({**self, **other})

class GlobalBase(type):
    def __getattr__(cls, key):
        return CustomDict({key: globals()[key]})

    def __getitem__(cls, keys):
        return CustomDict({key: globals()[key] for key in keys})

class G(metaclass=GlobalBase):
    pass

x, y, z = 0, 1, 2

print('method 1:', G['x', 'y', 'z']) # Outcome: method 1: {'x': 0, 'y': 1, 'z': 2}
print('method 2:', G.x + G.y + G.z) # Outcome: method 2: {'x': 0, 'y': 1, 'z': 2}

0

Con python-varnameusted puede hacerlo fácilmente:

pip install python-varname

from varname import Wrapper

foo = Wrapper(True)
bar = Wrapper(False)

your_dict = {val.name: val.value for val in (foo, bar)}

print(your_dict)

# {'foo': True, 'bar': False}

Descargo de responsabilidad: soy el autor de esa biblioteca python-varname.


-1
>>> a = 1
>>> b = 1
>>> id(a)
34120408
>>> id(b)
34120408
>>> a is b
True
>>> id(a) == id(b)
True

de esta forma, obtenga varname para quizás 'a' o 'b'.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.