我希望能够以字符串的形式获取变量的名称,但我不知道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(),所以我猜有一种方法。


当前回答

它不会返回变量的名称,但您可以轻松地从全局变量创建字典。

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}

其他回答

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

我写了包巫术健壮地做这种魔法。你可以这样写:

from sorcery import dict_of

my_dict = dict_of(foo, bar)

大多数对象没有__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)

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

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

我根据这个问题的答案写了一个简洁有用的函数。我把它放在这里,以防有用。

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)

用法:

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