【问题标题】:Simpler way to create dictionary of separate variables?创建单独变量字典的更简单方法?
【发布时间】:2026-01-25 13:20:05
【问题描述】:

我希望能够将变量的名称作为字符串获取,但我不知道 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(),所以我想是有办法的。

【问题讨论】:

  • 由于人们似乎对所要求的内容感到困惑,我将在此重申,因为这是一个有趣的问题。给定一个数组 [foo, bar, baz] 你想要一个像 {'foo': foo, 'bar': bar, 'baz': baz} 这样的字典,但你不知道数组中有哪些变量。所以提问者问你如何在python中将变量的名称作为字符串获取。现在希望人们可以浏览糟糕的响应,找到几个地方,让您了解为什么这在 python 中并不是一个好主意。
  • 技术的一个用途是简化字符串格式化调用:'{var} {foo} {bar}'.format(**named(var, foo, bar)),其中“named”是返回所描述的 dict('var': var) 的函数。
  • 我认为这实际上是一个糟糕的问题,因为名称被映射到对象,您可以有多个名称指向同一个对象,而且我从未见过任何需要实现反转该映射的目标。所以这里接受错误答案的事实是没有意义的——如果谷歌搜索把你带到这里,你显然是在问错误的问题。
  • 这是一个调试的好主意!

标签: python string variables


【解决方案1】:

正如 unwind 所说,这并不是您在 Python 中真正要做的事情 - 变量实际上是对象的名称映射。

不过,这里有一种方法可以尝试:

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

【讨论】:

  • 这个想法有好处,但请注意,如果两个变量名引用相同的值(例如True),则可能会返回一个意外的变量名。
  • 为什么是id(v) == id(a) 而不是v is a?对于绑定到多个变量的对象,例如整数、字符串和任何类似实现的用户定义类型,这将失败。
  • 是的,v is a 会是更好的选择。是的,考虑到可能出现的所有潜在陷阱,这当然很危险! ;-)
  • @e-satis 我很惊讶您没有将此答案标记为答案,因为我同意您的评论,即 rlotun 更接近它的初始“精神”,因为它允许发现名字。此外,S.Lott 的回答根本没有回答您的问题......
  • “矫枉过正和危险”......并且使用 eval 不是吗?
【解决方案2】:

我非常想做这件事。这个 hack 与 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]

【讨论】:

  • @keflavich 我非常喜欢这种方法,现在不时使用它。但是我不能让它在函数内部工作。我想有“更好”的方法可以做到这一点,但没有一个像 nbubis 所说的那样简单。您是否能够在函数 keflavich 中使用它? This 是我问这个问题的地方。
  • 请注意,在 Python 3 中,iteritems() 被替换为 items()
  • 这是不可靠的:spam = 1; blah = 1; blah_name = [ k for k,v in locals().items() if v is blah][0]; print(blah_name) 输出 spam
  • @andreasdr 那是因为spam = 1, blah = 1; assert spam is blah。比较原始数据类型时,解决方案会中断。
【解决方案3】:

你想这样做吗?

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

例子

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

【讨论】:

  • rlotun 更接近它最初的“精神”,因为它允许发现名称。我会使用你的两个答案。或者也许只是用我该死的手打字。有些事情并没有那么自动化......
  • @e-satis:要让@rlotun 工作,您必须提供变量列表。如果您有变量列表,那么“发现”它们的名称有什么意义?
  • 为什么使用 eval 而不是显式使用局部变量和全局变量?
  • @Roger Pate:因为我不知道整个练习的重点是什么。
  • 这个答案没有回答所提出的问题。 如果你有变量列表,“发现”它们的名字有什么意义?避免重复,这样就可以编写 magic_print(x) 而不是 print('x: ' + x) 并获得相同的输出,而无需两次编写变量名。
【解决方案4】:

这是一个黑客。它不适用于所有 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}

请注意,这种 hack 是脆弱的:

make_dict(bar,
          foo)

(在 2 行上调用 make_dict)将不起作用。

而不是尝试从 foobar 生成字典, 从字符串 variable names 'foo''bar' 生成字典会更加 Pythonic:

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

【讨论】:

  • +1 用于智能破解。当然,trace back 很慢,使用起来可能会很慢。
  • +1111111!!!!是的,它很慢,但是当用来替换 print("a_very_long_name: {}'.format(a_very_long_name)) 时谁在乎!
【解决方案5】:

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

【讨论】:

  • 是的,我知道,我的问题很简单,但我期待更多类似“get_var_tags(var)[0]”的内容。
【解决方案6】:

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

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

我不确定我是否将它放在正确的位置,但我认为它可能会有所帮助。我希望是的。

【讨论】:

  • 那么通过你的头部检查,它是否解释了变量/名称可以在代码中的不同时间指向不同事物的事实?例如,myconnection 可能在某个时间点指向一个布尔值,在另一个时间点指向一个整数,在代码执行的另一个时间点指向一个套接字连接??
【解决方案7】:

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

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

【讨论】:

    【解决方案8】:

    我发现,如果您已经有一个特定的值列表,那就是@S 描述的方式。洛茨是最好的;但是,下面描述的方法可以很好地在整个代码中添加所有变量和类没有需要提供变量名称,尽管您可以根据需要指定它们。可以扩展代码以排除类。

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

    输出:

    {'baz': 3, 'foo': 1, 'bar': 2}
    {'foo': 1}
    {'foo': 1, 'bar': 2}
    

    【讨论】:

      【解决方案9】:

      在 python 3 中这很容易

      myVariable = 5
      for v in locals():
        if id(v) == id("myVariable"):
          print(v, locals()[v])
      

      这将打印:

      我的变量 5

      【讨论】:

      • 这类似于 rlotun 的方法,但更简单一些
      • -1。打开一个新的解释器窗口并尝试for v in locals()
      • 我不太明白你的意思?
      • 这会报错:RuntimeError: dictionary changed size during iteration...
      • 不过你可以做到for v in list(locals()):
      【解决方案10】:

      Python3.使用检查来捕获调用本地命名空间,然后使用此处提供的想法。如前所述,可以返回多个答案。

      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
      

      【讨论】:

      • 很好的答案,但对我来说最好是: ... id(eval(name, None, frame.f_back.f_locals)) == ...
      【解决方案11】:

      这是我创建的用于读取变量名的函数。它更通用,可以用于不同的应用程序:

      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]
      

      在指定问题中使用它:

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

      【讨论】:

        【解决方案12】:

        在阅读线程时,我看到了很多摩擦。很容易给予 一个不好的答案,然后让某人给出正确的答案。无论如何,这是我找到的。

        来自:[effbot.org] (http://effbot.org/zone/python-objects.htm#names)

        名称有点不同——它们并不是对象的真正属性,而且对象本身也不知道它叫什么。

        一个对象可以有任意数量的名字,或者根本没有名字。

        名称存在于命名空间中(例如模块命名空间、实例命名空间、函数的本地命名空间)。

        注意:它说对象本身不知道它叫什么,所以这就是线索。 Python 对象不是自引用的。然后它说,名称存在于命名空间中。我们在 TCL/TK 中有这个。所以也许我的回答会有所帮助(但确实对我有帮助)

        jj = 123 打印 eval("'" + str(id(jj)) + "'") 打印目录()

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

        所以列表末尾有“jj”。

        将代码改写为:

        jj = 123 打印 eval("'" + str(id(jj)) + "'") 对于 dir() 中的 x: 打印 id(eval(x))
        161922920 ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'jj'] 3077447796 136515736 3077408320 3077656800 136515736 161922920

        这个讨厌的代码 id 是变量/对象/whatever-you-pedantics-call-it 的名称。

        原来如此。当我们直接查找'jj'的内存地址时,就像我们在全局名称空间中查找字典时一样。我相信你可以做一个功能来做到这一点。只需记住您的变量/对象/wypci 所在的命名空间即可。

        QED。

        【讨论】:

        • 这里有两个 eval 的疯狂用法。第一个与:print id(jj) 完全相同。第二个只是查找名称,使用vars() 可以更轻松地完成。
        【解决方案13】:

        我编写了包sorcery 来稳健地执行这种魔法。你可以写:

        from sorcery import dict_of
        
        my_dict = dict_of(foo, bar)
        

        【讨论】:

          【解决方案14】:

          也许我想多了,但是..

          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'
          

          【讨论】:

          • 太棒了!这就是我一直在寻找的。谢谢@rh0dium...\n variable = 1 \n [k for k,v in locals().items() if id(variable) == id(v)] \n Out[14]: ['variable']
          【解决方案15】:
          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)
          

          【讨论】:

            【解决方案16】:

            我将解决方案上传到pypi。它是一个模块,定义了 C# 的 nameof 函数的等效项。

            它遍历被调用帧的字节码指令,获取传递给它的变量/属性的名称。这些名称位于函数名称后面的LOAD 指令的.argrepr 中。

            【讨论】:

              【解决方案17】:

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

              除了print("my_var")之外,您对print(my_var.__name__)还有什么期望?可以直接直接使用字符串吗?

              你可以“切片”一个字典:

              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)
              

              【讨论】:

              • +1 但我知道 name 不存在,为什么每个人都接受这个“类似”的东西?您的解决方案不能解决问题,因为我不想对名称进行硬编码,否则我会执行我在问题中已经给出的 dict 解决方案。
              • @e-satis:如果简单地使用 locals() 中的所有内容就可以解决您的问题,我不知道您在问什么。我猜你可以调用some_func(var),所以我试图指出距离some_func("var") 不远,dictslice 允许你获取多个变量的名称-值映射一次。
              【解决方案18】:

              好吧,我几天前遇到了同样的需求不得不得到一个变量的name,它指向对象本身。

              为什么这么有必要?

              简而言之,我正在为 Maya 构建一个插件。核心插件是使用 C++ 构建的,但 GUI 是通过 Python 绘制的(因为它不是处理器密集型的)。由于我目前还不知道如何从插件中return 多个值,除了默认的MStatus,因此要在 Python 中更新字典我必须传递变量的名称,指向实现 GUI 并包含字典本身的对象,发送到插件,然后使用 MGlobal::executePythonCommand()Maya 的全局范围更新字典。

              为此,我所做的是:

              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
              

              我知道这不是globals 中的完美解决方案,许多键可能指向同一个对象,例如:

              a = foo()
              b = a
              b.name()
              >>>b
              or
              >>>a
              

              并且该方法不是线程安全的。如果我错了,请纠正我。

              至少这种方法解决了我的问题,方法是获取全局范围内指向 object 本身的任何变量的 name 并将其传递给插件, 作为参数,因为它在内部使用。

              我在int(原始整数类)上试过这个,但问题是这些原始类没有被绕过(如果错误,请更正使用的技术术语)。您可以重新实现int,然后执行int = foo,但a = 3 永远不会是foo 的对象,而是原语的对象。要克服这个问题,您必须 a = foo(3) 才能让 a.name() 工作。

              【讨论】:

                【解决方案19】:

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

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

                【讨论】:

                  【解决方案20】:

                  我正在解决类似的问题。 @S.Lott 说“如果你有变量列表,那么‘发现’它们的名字有什么意义?”我的回答只是看看它是否可以完成,以及是否出于某种原因您想按类型将变量排序到列表中。所以无论如何,在我的研究中,我遇到了这个线程,我的解决方案有点扩展,并且基于@rlotun 解决方案。另一件事,@unutbu 说,“这个想法有优点,但请注意,如果两个变量名引用相同的值(例如 True),那么可能会返回一个意外的变量名。”在这个练习中,这是正确的,所以我通过对每种可能性使用类似于此的列表理解来处理它:isClass = [i for i in isClass if i != 'item']。没有它,“项目”将显示在每个列表中。

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

                  【讨论】:

                  • 我要解决的问题是名称不是对象的属性。单个对象可能有多个名称,或者根本没有名称。例如,您在代码中添加了pi = pie,您将在isFloat 列表中获得一个额外的条目。如果您将tuple_1[0] 添加到您的mixedDataTypes 列表中,尽管“one”在您的代码中出现了两次,但不会找到它的名称(尽管由于字符串实习,它们都将引用同一个对象)。跨度>
                  • @Blckknght --- 我同意。这只是另一种方式来做一些真正不应该做的事情。我并没有说它会产生独特的结果或它是绝对可靠的。在这样做时,我发现使用pie 作为变量会导致不需要的输出,这是因为它们都是math 库的一部分。对我来说,这只是一个练习,看看它是否可以完成,即使最终结果并不完美。在我通过书本学习这种语言的过程中,仅此而已。在我看来,如果你真的想学习这门语言,那么你必须玩“假设”,看看你想出了什么。
                  【解决方案21】:

                  你可以使用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
                  

                  另一个例子:

                  >>> d = EasyDict(log=False)
                  >>> d.debug = True
                  >>> d.items()
                  [('debug', True), ('log', False)]
                  

                  【讨论】:

                    【解决方案22】:

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

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

                    【讨论】:

                      【解决方案23】:

                      虽然这可能是一个糟糕的想法,但它与 rlotun 的答案大致相同,但它会更频繁地返回正确的结果。

                      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
                      

                      你这样称呼它:

                      bar = True
                      foo = False
                      bean = False
                      fooName = getVarName(lambda: foo)
                      print(fooName) # prints "foo"
                      

                      【讨论】:

                        【解决方案24】:

                        应该得到列表然后返回

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

                        【讨论】:

                          【解决方案25】:

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

                          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}
                          

                          【讨论】:

                            【解决方案26】:

                            使用python-varname,您可以轻松做到:

                            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}
                            

                            免责声明:我是那个 python-varname 库的作者。

                            【讨论】:

                              【解决方案27】:
                              >>> a = 1
                              >>> b = 1
                              >>> id(a)
                              34120408
                              >>> id(b)
                              34120408
                              >>> a is b
                              True
                              >>> id(a) == id(b)
                              True
                              

                              通过这种方式获取可能为“a”或“b”的 varname。

                              【讨论】: