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


当前回答

我认为我的问题将有助于说明为什么这个问题是有用的,它可能会让你更深入地了解如何回答这个问题。我写了一个小函数来对代码中的各种变量进行快速内联头部检查。基本上,它列出了变量名、数据类型、大小和其他属性,因此我可以快速捕捉到我所犯的任何错误。代码很简单:

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

所以如果你有一些复杂的字典/列表/元组的情况,让解释器返回你分配的变量名会很有帮助。例如,这里有一个奇怪的字典:

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'>

我不确定我是否把它放在正确的地方,但我想它可能有帮助。我希望如此。

其他回答

I was working on a similar problem. @S.Lott said "If you have the list of variables, what's the point of "discovering" their names?" And my answer is just to see if it could be done and if for some reason you want to sort your variables by type into lists. So anyways, in my research I came came across this thread and my solution is a bit expanded and is based on @rlotun solution. One other thing, @unutbu said, "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." In this exercise that was true so I dealt with it by using a list comprehension similar to this for each possibility: isClass = [i for i in isClass if i != 'item']. Without it "item" would show up in each list.

__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 []
'''

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

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

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

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