如何在Python中打印变量名?

134

假设我有一个名为choice的变量,它的值为2。我如何访问变量的名称?类似于以下内容:

In [53]: namestr(choice)
Out[53]: 'choice'

用于创建字典。有一种好的方法可以做到这一点,我只是不知道怎么做。

编辑:

这样做的原因是,我正在运行一些数据分析程序,需要在运行时调整多个参数,我想要调整或不调整这些参数。我从一个格式为 .config 的文件中读取了上次运行时使用的参数。

filename
no_sig_resonance.dat

mass_peak
700

choice
1,2,3
当要求输入值时,先前使用的值会显示出来,如果输入为空字符串,则使用先前使用的值。
我的问题是,在编写这些值已被扫描到的字典时。如果需要参数,我运行get_param访问文件并查找参数。
我认为通过一次读取.config文件并从中生成字典来避免这个问题。我最初避免这样做是因为...我不再记得的原因。更新代码的完美机会!

1
http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables - jfs
该链接提供了一些图片,仅需2分钟即可教会您Python中的名称是什么。 - jfs
1
也相关:https://dev59.com/lnNA5IYBdhLWcg3wgeKk - sdaau
19
在 Stack Overflow 上,很少有比质疑一个问题本身存在更糟糕的事情了。 - rtphokie
2
最后,使用Python 3.8 f-string =语法的完全有效的解决方案:https://dev59.com/UVwY5IYBdhLWcg3w9r7a#57225950 - M. Heuer
显示剩余3条评论
8个回答

153
< p >如果你坚持,这里有一些使用inspect的可怕解决方案。

import inspect, re

def varname(p):
  for line in inspect.getframeinfo(inspect.currentframe().f_back)[3]:
    m = re.search(r'\bvarname\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)', line)
    if m:
      return m.group(1)

if __name__ == '__main__':
  spam = 42
  print varname(spam)

我希望它能激发您重新评估您所面临的问题,并寻找另一种方法。


1
inspect.currentframe().f_back.f_locals有相关的用例。 - jfs
192
有时候经过一夜的调试会让我们做出一些让自己感到不太光彩的事情。 - Jake
16
因为字面上让我大声笑了,所以我点了赞。 - Enteleform
10
我喜欢Jake的评论,尽管离问题发布已经五年了,但仍有70多个人投了赞,这些人和我一样,在绝望的时候不情愿地搜索如何做这件不光彩的事情。 - M. Lautaro
它不能与列表推导一起使用。a,b=1,2; print([varname(x) for x in [a,b]]) 输出 ['x', 'x'] - shahar_m
1
是的,当它传递给函数 varname 时,变量名确实是 x - ticster

114

回答你的原始问题:

def namestr(obj, namespace):
    return [name for name in namespace if namespace[name] is obj]

例子:

>>> a = 'some var'
>>> namestr(a, globals())
['a']

正如@rbright已经指出的那样,无论你做什么,可能都有更好的方法。


5
如果有多个变量名引用同一个值,这种方法就会失败。 - Greg Hewgill
2
@Greg Hewgill:你可能已经注意到namestr返回的是列表。这是一个提示,说明可能有多个名称。 - jfs
1
我会说大多数整数不共享它们的表示方式。 - jfs
3
我喜欢你的答案代码流畅,但在代码中可能会使用多次重复的整数… 叹气 - physicsmichael
2
@Piotr Dobrogost: “share their representions” 指的是 CPython 优化,它缓存小整数,因此其中一个集合不可计数,它是有限的。 - jfs
显示剩余4条评论

17

如果你正在尝试这样做,那就意味着你正在做一些错误的事情。考虑使用dict代替。

def show_val(vals, name):
    print "Name:", name, "val:", vals[name]

vals = {'a': 1, 'b': 2}
show_val(vals, 'b')

输出:

Name: b val: 2

4
原始问题不合理。它只是一个简单的词典,或者也许可以尝试使用其他语言。 - S.Lott
假设我有一个变量choice = '他选择了3!'。在指定键时,我能否将其添加到字典中而无需手动输入“choice”? - physicsmichael
1
key = "choice"; print vals[key] - recursive

10
与其询问特定解决方案的详细信息,我建议描述您面临的问题;我认为您会得到更好的答案。我之所以这样说是因为几乎肯定有更好的方法来完成您正在尝试做的任何事情。在任何语言中,访问变量名称通常不需要解决问题。
话虽如此,所有变量名称都已经在字典中,并可通过内置函数localsglobals进行访问。根据您要检查的范围使用正确的字典。
检查这些字典的少数常见惯用语之一是进行简单的字符串插值:
>>> first = 'John'
>>> last = 'Doe'
>>> print '%(first)s %(last)s' % globals()
John Doe

这种做法通常比其他方式更易读,即使需要通过变量名称进行检查。

我想尝试打印“first”和“last”,即我调用引用的值,而不是它们相等的值。 - physicsmichael
我知道,我只是想让你知道人们通常查看那些字典的一个原因。通常情况下,您不应该需要它们。除非您想提供更多细节,否则只需在其中搜索您要查找的内容即可。例如,globals().keys()。 - Ryan Bright

9

你不能像其他语言一样定义变量,在Python中我们只有名字。

例如:

> a = [1,2,3]
> b = a
> a is b
True

这两个变量中哪一个是正确的?ab没有区别。

以前有一个类似的问题


43
A和B之间的区别在于名称。 - Kenan Banks
1
gs是正确的。a和b引用同一对象,因此接收此对象的函数无法知道在函数调用中使用了哪个名称来引用该对象。 - dF.
3
他的说法有点正确,在Python中你无法编写一个函数进行微分。不过,完全可以有一个内置函数来实现这个功能。 - Kenan Banks
dis.dis() 返回一些名称(并非总是)。 - jfs
23
Python中是有变量的。这是一个错误的信息。你可能想说的是,“Python中的变量与C中的变量工作方式不同。” - Ned Batchelder
显示剩余2条评论

5
这个对你有用吗?
>>> def namestr(**kwargs):
...     for k,v in kwargs.items():
...       print "%s = %s" % (k, repr(v))
...
>>> namestr(a=1, b=2)
a = 1
b = 2

在你的例子中:
>>> choice = {'key': 24; 'data': None}
>>> namestr(choice=choice)
choice = {'data': None, 'key': 24}
>>> printvars(**globals())
__builtins__ = <module '__builtin__' (built-in)>
__name__ = '__main__'
__doc__ = None
namestr = <function namestr at 0xb7d8ec34>
choice = {'data': None, 'key': 24}

4

在Python中,使用急切求值(eager evaluation)的情况下,变量在任何时候被查看时本质上都会转换为它们的值(引用原意)。尽管如此,Python确实有内置的命名空间。例如,locals()将返回一个字典,将函数变量的名称映射到它们的值,而globals()针对一个模块执行同样的操作。因此:

for name, value in globals().items():
    if value is unknown_variable:
        ... do something with name

请注意,您无需导入任何内容即可访问locals()和globals()。
此外,如果一个值有多个别名,那么遍历命名空间只会找到第一个。

1
如果有多个变量名称具有相同的值,则此操作将失败。 - Greg Hewgill
1
虽然没什么可以做的,但我会添加一个警告。 ;) - Nikhil

3
对于如何读取配置参数的修订问题,我强烈建议您节省时间和精力并使用 ConfigParser或(我更喜欢的工具) ConfigObj。它们可以完成您需要的所有操作,易于使用,并且其他人已经担心如何使它们正常工作!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接