TL;DR
使用来自python-varname 的Wrapper 助手:
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 上提交问题。
长答案
有可能吗?
是和否。
我们在运行时检索变量名,所以我们需要调用一个函数来使我们能够访问之前的帧来检索变量名。这就是我们需要Wrapper 的原因。在该函数中,在运行时,我们正在解析前一帧中的源代码/AST 节点以获取确切的变量名称。
但是,之前帧中的源代码/AST 节点并不总是可用,或者它们可能被其他环境修改(例如:pytest 的assert 语句)。一个简单的例子是代码通过exec() 运行。即使我们仍然能够从字节码中检索到一些信息,但它需要付出太多的努力,而且还容易出错。
怎么做?
首先,我们需要确定给定变量的帧。它并不总是简单的直接前一帧。例如,我们可能有另一个函数的包装器:
from varname import varname
def func():
return varname()
def wrapped():
return func()
x = wrapped()
在上面的示例中,我们必须跳过wrapped 中的帧才能到达正确的帧x = wrapped(),以便我们能够定位x。 varname 的参数 frame 和 ignore 允许我们跳过其中一些中间帧。在 README 文件和包的 API 文档中查看更多详细信息。
然后我们需要解析 AST 节点来定位变量被赋值(函数调用)的位置。这并不总是一个简单的任务。有时可能会有复杂的 AST 节点,例如,x = [wrapped()]。我们需要通过遍历 AST 树来识别正确的赋值。
它有多可靠?
一旦我们确定了分配节点,它就是可靠的。
varname 完全依赖executing 包来寻找节点。确保执行检测的节点是正确的(另见this)。
它部分适用于应用其他 AST 魔法的环境,包括 pytest、ipython、macropy、birdseye、reticulate with R 等。无论是执行还是 varname 都不能 100% 地适用于这些环境。
我们需要一个包吗?
嗯,是的,又不是。
如果您的场景很简单,@juan Isaza 或 @scohe001 提供的代码可能足以让您处理在直接前一帧定义变量且 AST 节点是简单赋值的情况。您只需返回一帧并在那里检索信息。
但是,如果场景变得复杂,或者我们需要采用不同的应用场景,你可能需要像python-varname这样的包来处理它们。这些场景可能包括:
- 在源代码不可用或 AST 节点不可访问时显示更友好的消息
- 跳过中间帧(允许在其他中间帧中包装或调用函数)
- 自动忽略来自内置函数或库的调用。例如:
x = str(func())
- 检索赋值左侧的多个变量名
- 等
f-string 怎么样?
就像@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 节点并在需要时评估它们会耗费资源。