博士TL;
使用python-varname中的Wrapper helper:
from varname.helpers import Wrapper
foo = Wrapper(dict())
# foo.name == 'foo'
# foo.value == {}
foo.value['bar'] = 2
对于列表理解部分,您可以执行:
n_jobs = Wrapper(<original_value>)
users = Wrapper(<original_value>)
queues = Wrapper(<original_value>)
priorities = Wrapper(<original_value>)
list_of_dicts = [n_jobs, users, queues, priorities]
columns = [d.name for d in list_of_dicts]
# ['n_jobs', 'users', 'queues', 'priorities']
# REMEMBER that you have to access the <original_value> by d.value
我是python-varname包的作者。如果你有任何问题,请告诉我,或者你可以在Github上提交问题。
长话短说
这可能吗?
是也不是。
我们在运行时检索变量名,因此需要调用一个函数,使我们能够访问前面的帧以检索变量名。这就是为什么我们需要一个包装器。在该函数中,在运行时,我们将解析前一帧中的源代码/AST节点,以获得确切的变量名。
然而,前几帧中的源代码/AST节点并不总是可用的,或者它们可以被其他环境修改(例如:pytest的assert语句)。一个简单的例子是代码通过exec()运行。尽管我们仍然能够从字节码中检索一些信息,但这需要太多的工作,而且也容易出错。
怎么做呢?
首先,我们需要确定给定变量的坐标系。它并不总是直接的前一帧。例如,我们可以为函数使用另一个包装器:
from varname import varname
def func():
return varname()
def wrapped():
return func()
x = wrapped()
在上面的例子中,我们必须跳过wrapped内部的帧,以获得正确的帧x = wrapped(),以便能够定位x。参数frame和ignore的varname允许我们跳过这些中间帧中的一些。在README文件和包的API文档中查看更多细节。
然后,我们需要解析AST节点,以定位变量被赋值(函数调用)的位置。这并不总是一个简单的任务。有时可能存在复杂的AST节点,例如x = [wrapped()]。我们需要通过遍历AST树来确定正确的赋值。
它有多可靠?
一旦我们确定了分配节点,它就是可靠的。
Varname完全依赖于执行包来查找节点。确保执行检测的节点是正确的(另见此)。
它部分适用于其他AST魔法应用的环境,包括pytest, ipython, macropy, birdseye, reticulate with R等。无论是执行还是varname都不能100%地在这些环境中工作。
我们需要一个包裹来做吗?
又一次,是又不是。
如果您的场景很简单,那么@juan Isaza或@scohe001提供的代码可能就足以处理这样的情况:变量定义在前面的直接帧上,AST节点是一个简单的赋值。你只需要返回一帧,并检索那里的信息。
但是,如果场景变得复杂,或者我们需要采用不同的应用程序场景,您可能需要一个像python-varname这样的包来处理它们。这些情况可能包括:
当源代码不可用或AST节点不可访问时,提供更友好的消息
跳过中间帧(允许函数在其他中间帧中被包装或调用)
自动忽略来自内置函数或库的调用。例如:x = str(func())
检索赋值左侧的多个变量名
等。
f弦呢?
就像@Aivar Paalberg提供的答案。它绝对是快速和可靠的。但是,它不是在运行时,这意味着在输出名称之前必须知道它是foo。但是使用varname,你不需要知道变量是什么:
from varname import varname
def func():
return varname()
# In external uses
x = func() # 'x'
y = func() # 'y'
最后
Python-varname不仅能够从赋值中检测变量名,而且还:
使用nameof直接检索变量名
检测下一个即时属性名,使用will
使用argname获取传递给函数的参数名/源
从它的文档中阅读更多。
然而,我想说的最后一句话是,尽量避免使用它。
因为您不能确保客户端代码将在源节点可用或AST节点可访问的环境中运行。当然,解析源代码、识别环境、检索AST节点并在需要时对它们进行评估都需要消耗资源。