假设我有一个名为
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
文件一次并从中生成字典来完全避免这个问题。我最初避免这样做的原因……我已不记得了。更新我的代码的完美情况!
如果你坚持的话,这里有一些可怕的基于检查的解决方案。
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)
我希望它能激励您重新评估您遇到的问题并寻找另一种方法。
def namestr(obj, namespace):
return [name for name in namespace if namespace[name] is obj]
示例:
>>> a = 'some var'
>>> namestr(a, globals())
['a']
我们可以使用
inspect
模块获取调用者的命名空间:
import inspect
def names_in_caller(obj, depth=2) -> list[str]:
"""Return *obj*'s names in the caller namespace.
Default *depth* is 2 meaning that caller's caller names
are returned
"""
f = inspect.currentframe()
for _ in range(depth):
f = f.f_back
return namestr(obj, f.f_locals)
示例:
>>> def f(n):
... n_name = name_in_caller(n) # find name in the caller
... return f"{n_name}={n}" # like f"{n=}" but with callers' name
...
>>> a = 1
>>> f(a)
"['a']=1"
>>> b = 1
>>> f(a)
"['a', 'b']=1"
正如 @rbright 已经指出的那样 无论你做什么,可能都有更好的方法。
如果您尝试这样做,则意味着您做错了什么。 考虑使用
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
我建议描述您面临的问题,而不是询问具体解决方案的细节;我想你会得到更好的答案。 我这么说是因为几乎可以肯定有一种更好的方法来完成您想要做的任何事情。 解决任何语言的问题通常都不需要以这种方式访问变量名。
也就是说,所有变量名都已经在字典中,可以通过内置函数locals和globals访问。 使用适合您正在检查的范围的正确型号。
检查这些字典的几个常见习惯用法之一是轻松进行字符串插值:
>>> first = 'John'
>>> last = 'Doe'
>>> print '%(first)s %(last)s' % globals()
John Doe
这种事情往往比其他选择更具可读性,尽管它需要按名称检查变量。
你不能,因为 Python 中没有变量,只有名称。
例如:
> a = [1,2,3]
> b = a
> a is b
True
这两个变量中哪一个现在是正确的变量?
a
和 b
之间没有区别。
之前有过一个类似的问题。
这样的东西对你有用吗?
>>> 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}
通过热切求值,只要您查看变量(释义),它们基本上就会变成它们的值。 也就是说,Python 确实有内置的命名空间。 例如,locals() 将返回一个字典,将函数的变量名称映射到它们的值,而 globals() 对模块执行相同的操作。 因此:
for name, value in globals().items():
if value is unknown_variable:
... do something with name
请注意,您不需要导入任何内容即可访问 locals() 和 globals()。
此外,如果一个值有多个别名,则迭代命名空间只会找到第一个别名。
对于如何读取配置参数的修改问题,我强烈建议您节省一些时间和精力并使用 ConfigParser 或(我喜欢的工具)ConfigObj。
它们可以完成您需要的一切,并且易于使用,其他人已经担心如何让它们正常工作!