我希望能够以字符串的形式获取变量的名称,但我不知道Python是否有那么多的自省功能。喜欢的东西:

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

我想这样做是因为我有一堆变量,我想把它们转换成一个字典,比如:

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

但我想要更自动的。

Python有locals()和vars(),所以我猜有一种方法。


当前回答

大多数对象没有__name__属性。(类、函数和模块可以;还有其他内置类型吗?)

除了print("my_var"),你还期望print(my_var.__name__)有什么?你能直接使用字符串吗?

你可以"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"})

另外:

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)

其他回答

我一直很想这么做。这个技巧与rlotun的建议非常相似,但它是一行代码,对我来说很重要:

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]

在python 2.7及更新版本中,还有字典理解,这使得它更短一些。如果可能的话,我会使用getattr代替eval (eval是邪恶的),就像在顶部的答案。Self可以是任何有你正在看的上下文的对象。它可以是一个对象或locals=locals()等。

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

这是一个黑客。它不能在所有Python实现发行版上工作(特别是那些没有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}

注意,这个黑客是脆弱的:

make_dict(bar,
          foo)

(在2行上调用make_dict)将无法工作。

与其尝试用foo和bar值生成dict, 从字符串变量名'foo'和'bar'中生成dict会更加python化:

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

这在Python中是不可能的,因为Python真的没有“变量”。Python有名称,同一个对象可以有多个名称。

在python3中,该函数将获取堆栈中最外层的名称:

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]

它在代码的任何地方都有用。遍历反向堆栈,寻找第一个匹配项。