views:

170

answers:

5

I would like to be able to get the name of a variable as a string but I don't know if Python has that much introspection capabilities. Something like:

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

I want to do that because I have a bunch of vars I'd like to turn into a dictionary like :

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

But I'd like something more automatic than that.

Python have locals() and vars(), so I guess there is a way.

+3  A: 

This is not possible in Python, which really doesn't have "variables". Python has names, and there can be more than one name for the same object.

unwind
yeah, I know, I made the question simple, but I was expecting more something like "get_var_tags(var)[0]".
e-satis
+1  A: 

Most objects don't have a __name__ attribute. (Classes, functions, and modules do; any more builtin types that have one?)

What else would you expect for print(my_var.__name__) other than print("my_var")? Can you simply use the string directly?

You could "slice" a 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"})

Alternatively:

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)
Roger Pate
+1 but I know that __name__ doesn't exist, why does everybody take this "something like" litteraly? Your solution doesn't solve the problem since I don't want to harcode the name, overwise I would do the dict solution I already gave in the question.
e-satis
@e-satis: If simply using everything in locals() solves your problem, I have no idea what you're asking. I'm guessing you're okay with calling `some_func(var)`, so I tried to point out there's not very far from `some_func("var")`, with *dictslice* allowing you to get the name-value mapping for multiple variables at once.
Roger Pate
+3  A: 

As unwind said, this isn't really something you do in Python - variables are actually name mappings to objects.

However, here's one way to try and do it:

 >>> a = 1
 >>> for k, v in list(locals().iteritems()):
         if id(v) == id(a):
             a_as_str = k
 >>> a_as_str
 a
 >>> type(a_as_str)
 'str'
rlotun
This idea has merit, but note that if two variable names reference the same value (e.g. `True`), then an unintended variable name might be returned.
unutbu
+1. Very ingenious, a bit overkill and dangerous though.
e-satis
Why `id(v) == id(a)` instead of `v is a`? This will fail for objects bound to multiple variables, such as ints, strings, and any similarly implemented user-defined types.
Roger Pate
Yes, `v is a` would be a better choice. And yes, certainly dangerous given all the potential pitfalls that could arise! ;-)
rlotun
A: 

This is a hack. It will not work on all Python implementations distributions (in particular, those that do not have 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}

Note that this hack is fragile:

make_dict(bar,
          foo)

(calling make_dict on 2 lines) will not work.

Instead of trying to generate the dict out of the values foo and bar, it would be much more Pythonic to generate the dict out of the string variable names 'foo' and 'bar':

dict([(name,locals()[name]) for name in ('foo','bar')])
unutbu
+1 for the smart hack. Of course, trace back are very slow so it may be slugish to use it.
e-satis
+2  A: 

Are you trying to do this?

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

Example

>>> 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}
S.Lott
Nice one S.Lott. Never far away from a Python question, ain't you? This is the closest we can get I guess, given that we apparently can't get access to the many names that point to a variable value. Not totally automatic, but close enough.
e-satis
@e-satis: What could be more automatic than this? What are you talking about? All variables are already in `locals`.
S.Lott
rlotun is closer to the initial "spirit" of it since it allows to discover the name. I will could use both your anwser. Or maybe just use my damn hand to type. Some things are just not made to be that automatized...
e-satis
@e-satis: For @rlotun's to work, you have to provide the list of variables. If you have the list of variables, what's the point of "discovering" their names?
S.Lott
Why eval instead of explicitly using locals and globals?
Roger Pate
@Roger Pate: Because I couldn't figure out what the point of the whole exercise was.
S.Lott