【问题标题】:Getting the name of a variable as a string获取变量名作为字符串
【发布时间】:2013-08-27 19:50:55
【问题描述】:

此线程讨论如何在 Python 中将函数名称作为字符串获取: How to get a function name as a string?

我怎样才能对变量做同样的事情?与函数相反,Python 变量没有__name__ 属性。

换句话说,如果我有一个变量,例如:

foo = dict()
foo['bar'] = 2

我正在寻找一个函数/属性,例如retrieve_name() 改为 create a DataFrame in Pandas from this list,其中列名由实际字典的名称给出:

# List of dictionaries for my DataFrame
list_of_dicts = [n_jobs, users, queues, priorities]
columns = [retrieve_name(d) for d in list_of_dicts] 

【问题讨论】:

  • 对于常量,您可以使用枚举,它支持检索其名称。
  • 我遇到了类似的问题。我意识到不是将原始数据存储为事物列表,而是可以将其存储为事物的字典,(如果需要,您可以轻松地从字典中动态生成列表)。例如,假设您有:my_dict = {'n_jobs': ..., 'users': ...}。然后您可以使用 my_dict['n_jobs'] 代替 n_jobs。无论如何,对我来说重要的是我只需要输入一次“n_jobs”,可以是 var 名称,也可以是 dict 键中的字符串。

标签: python variables


【解决方案1】:

使用 Python 3.8 可以简单地使用f-string 调试功能:

>>> foo = dict()
>>> f'{foo=}'.split('=')[0]
'foo' 

这种方法的一个缺点是,为了打印'foo',您必须自己添加f'{foo=}'。换句话说,您已经必须知道变量的名称。也就是说,上面的代码sn -p和刚才的完全一样

>>> 'foo'

请在此处查看可能适用于回答该问题的其他答案。

【讨论】:

  • 不错!如果你想获得一个属性的名称而不是一个对象,你可以f'{foo=}'.split('=')[0].split('.')[-1]
  • 这到底有什么用?只有手动写“foo”才能得到结果“foo”。它不能解决 OP 问题。
  • 它在回答时确实解决了 OP 问题。随着时间的推移,这个问题已经“演变”,有一个问题是哪个标题与内容相当。然后是熊猫部分的更新,清楚地标有“更新”。然后它被编辑并成为问题的一部分,这被遗漏了:I am looking for a function/attribute, e.g. retrieve_name: retrieve_name(foo) that returns the string 'foo' 。现在任何“迟到”的人都会想知道这些答案到底是关于什么的......
  • 许多人似乎缺少的一点(@ Hugo 除外)是,为了能够写 f'{foo=}'.split('=')[0],您显然 已经知道变量的名称
  • @Hugo 我正在寻找这个以节省打字。我有许多熊猫数据框要导出到 .xlsx,其中数据框的名称是输出 excel 文件中工作表的名称,如下所示: vel.to_excel(writer,sheet_name='vel'), vol.to_excel( writer,sheet_name='vol'), area.to_excel(writer,sheet_name='area')。它将节省打字,减少出错的机会,并使代码更具可读性,以将数据帧放入列表中,然后在 for 循环中导出 - for df in df_list: df.to_excel(writer,sheet_name=df.名称)或类似名称。
【解决方案2】:

Python 中唯一具有规范名称的对象是模块、函数和类,当然,在定义函数或类或导入模块后,不能保证此规范名称在任何命名空间中具有任何意义。这些名称也可以在创建对象后进行修改,因此它们可能并不总是特别值得信赖。

你想做的事是不可能的without recursively walking the tree of named objects;名称是对对象的单向引用。一个普通的或普通的 Python 对象不包含对其名称的引用。想象一下,如果每个整数、每个字典、每个列表、每个布尔值都需要维护一个表示引用它的名称的字符串列表!这将是一场噩梦,对程序员几乎没有好处。

【讨论】:

  • 谢谢。但是为什么 Python 会为函数这样做呢? (即一种 Python 对象)
  • 你的陈述“这根本不可能”是假的,就像@scohe001 showed。 Python 的变量名数据库就像任何其他关系数据库一样,您始终可以“反向”搜索相关对象并返回第一个找到的或任何给定变量的整个有效变量名集。
  • @hobs 你在技术上是正确的......最好的正确。然而,在实践中,一个对象有很多潜在的名称,因此尝试获取它们比尝试获取它们更麻烦。
  • @hobs 好吧,一个对象可以是列表或字典或其他容器的成员,或者是对象属性...所以在这种情况下,您需要找到包含的名称对象也...并且它也可能包含在另一个对象中...因此您可能需要递归查找名称,直到您到达当前代码可以访问的对象。这似乎有很多容易出错的代码来编写和调试,但并没有太多好处。
  • 如果你在你的“不可能”断言附近链接到他的“可能性”,或者甚至纠正它,我相信@scohe001 会很感激,因为他提供的可能性是正确的、简单的,并且提供OP 需要什么(globals() 根中的一个 var),我将其解释为确实值得的“好处”。
【解决方案3】:

即使变量值不指向名称,您也可以访问每个已分配变量及其值的列表,所以我很惊讶只有一个人建议在此处循环查找您的 var 名称。

有人在该答案中提到,您可能必须遍历堆栈并检查每个人的本地和全局以找到 foo,但如果在您调用此 retrieve_name 函数的范围内分配了 foo,您可以使用inspectcurrent frame 来获取所有这些局部变量。

我的解释可能有点过于冗长(也许我应该少用“foo”字),但这是代码中的样子(请注意,如果有多个变量分配给相同的值,你会得到这两个变量名):

import inspect

x, y, z = 1, 2, 3

def retrieve_name(var):
    callers_local_vars = inspect.currentframe().f_back.f_locals.items()
    return [var_name for var_name, var_val in callers_local_vars if var_val is var]

print(retrieve_name(y))

如果您从另一个函数调用此函数,例如:

def foo(bar):
    return retrieve_name(bar)

foo(baz)

如果你想要baz 而不是bar,你只需要进一步返回一个范围。这可以通过在caller_local_vars 初始化中添加一个额外的.f_back 来完成。

在此处查看示例:ideone

【讨论】:

  • @theodox 我绝对同意,因为这可能会与import hooksironpythonjython 配合使用
  • 这行不通。原子变量没有它们的名称作为属性。所以如果你有a, b = 2, 2retrieve_name(a)retrieve_name(b) 都将返回['a', 'b']['b', 'a']
  • @tomas 实际上,这是 cPython 优化的实现细节,其中 255 以下的整数基本上是单例,因此分配这些值的任何变量都将有效地返回 true 以进行 is 比较
  • 是否有这样的模式来获取传递的变量的名称?例如def foo(bar): retrieve_name(bar) 将始终返回 bar,但是如果您希望 foo(baz) 返回 baz) 而不是 bar,该怎么办?
  • @SumNeuron 您只需要修改分配callers_local_vars 的行以进一步向后移动一个范围,这样它将查看调用foo 的任何范围。将行更改为inspect.currentframe().f_back.f_back.f_locals.items()(注意额外的f_back)。
【解决方案4】:

TL;DR

使用来自python-varnameWrapper 助手:

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 节点并不总是可用,或者它们可能被其他环境修改(例如:pytestassert 语句)。一个简单的例子是代码通过exec() 运行。即使我们仍然能够从字节码中检索到一些信息,但它需要付出太多的努力,而且还容易出错。

怎么做?

首先,我们需要确定给定变量的帧。它并不总是简单的直接前一帧。例如,我们可能有另一个函数的包装器:

from varname import varname

def func():
  return varname()

def wrapped():
  return func()

x = wrapped()

在上面的示例中,我们必须跳过wrapped 中的帧才能到达正确的帧x = wrapped(),以便我们能够定位xvarname 的参数 frameignore 允许我们跳过其中一些中间帧。在 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这样的包来处理它们。这些场景可能包括:

  1. 在源代码不可用或 AST 节点不可访问时显示更友好的消息
  2. 跳过中间帧(允许在其他中间帧中包装或调用函数)
  3. 自动忽略来自内置函数或库的调用。例如:x = str(func())
  4. 检索赋值左侧的多个变量名

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 节点并在需要时评估它们会耗费资源。

【讨论】:

  • 好的,终于明白了!使用以下pip3 install python-varname==0.1.5 安装;使用from varname import nameof 导入
  • @Tillus 固定在v0.2.0
  • 虽然python-varname master 分支具有nameofcaller 参数,这在技术上允许消除问题中的columns 示例(由于列表理解创建的额外范围),如果您尝试通过普通的for 循环填充columns,这将无济于事。在这种情况下,消除歧义是不可能的。对象不携带任何“原始”或“真实”变量的信息。 (另外,caller 参数未发布。)
  • @PanwenWang,您介意将varname 添加到任何 anaconda 频道吗?
  • @ted930511 我不介意其他人是否将其添加到任何 conda 频道。欢迎您通过将其添加到频道并使其保持最新来成为该项目的贡献者。
【解决方案5】:

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

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

【讨论】:

  • 干得好!虽然我尝试retrieve_name(SomeClass.some_attribute) 它不起作用。你能在这方面提供进一步的帮助吗?
  • 这与布尔变量有关。我最终得到stop_on_error
【解决方案6】:

我不相信这是可能的。考虑以下示例:

>>> a = []
>>> b = a
>>> id(a)
140031712435664
>>> id(b)
140031712435664

ab 指向同一个对象,但是对象不知道指向它的变量是什么。

【讨论】:

  • 当然可以通过扩展reference counting来建立双向关系。这个answer(和其他一些)甚至提供了一个实现。
【解决方案7】:
def name(**variables):
    return [x for x in variables]

它是这样使用的:

name(variable=variable)

【讨论】:

  • 这不会返回所需变量的名称,而是“变量”。例如 - 使用name(variable=variable) 将输出['variable'],使用name(variable=another_variable) 输出['another_variable'] 而是['variable']
  • 实际上它按预期工作。您只需用您的变量替换两个«variable»。它将返回一个包含 first 变量名称字符串的单元素列表。例如:&gt;&gt;&gt; a = []&gt;&gt;&gt; b = a&gt;&gt;&gt; name(a=b)['a']&gt;&gt;&gt; name(b=a)['b']`
  • 这只是一种落后的写法 varname = 'variable'。 name 函数中的第一个“变量”不是变量,而是关键字名称。相当于写lambda name, var: name
  • 我同意 Sharir 的观点。 OP的问题是有一个函数name_of,它可以用来遍历一个列表并获取与列表的每个值关联的变量名。
【解决方案8】:
>> my_var = 5
>> my_var_name = [ k for k,v in locals().items() if v == my_var][0]
>> my_var_name 
'my_var'

如果 myvar 指向另一个变量时出现错误,请试试这个(@mherzog 建议)-

 >> my_var = 5
>> my_var_name = [ k for k,v in locals().items() if v is my_var][0]
>> my_var_name 
'my_var'

locals() - 返回包含当前作用域的局部变量的字典。 通过遍历这个字典,我们可以检查值等于定义变量的键,只需提取键就会给我们字符串格式的变量文本。

from(稍作改动后) https://www.tutorialspoint.com/How-to-get-a-variable-name-as-a-string-in-Python

【讨论】:

  • 如果myvar 指向另一个变量,代码中的if 语句会出错。但是,如果您使用is`` rather than ==``,它会很好地工作。 IE。更改为my_var_name = [ k for k,v in locals().items() if v is e][0] ```
  • @mherzog this "is" 工作,但是如果我们想知道指向的变量名而不是索引变量名,我们可能需要选择 [1] 或其他
  • 有没有办法将其扩展到全局变量而不仅仅是本地变量?
【解决方案9】:

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

from sorcery import dict_of

columns = dict_of(n_jobs, users, queues, priorities)

并将其传递给数据框构造函数。相当于:

columns = dict(n_jobs=n_jobs, users=users, queues=queues, priorities=priorities)

【讨论】:

【解决方案10】:

这是一种方法。我不会推荐任何重要的东西,因为它会很脆弱。但可以做到。

创建一个使用inspect 模块的函数来查找调用它的源代码。然后您可以解析源代码以识别您想要检索的变量名称。例如,这里有一个名为autodict 的函数,它接受一个变量列表并返回一个将变量名称映射到它们的值的字典。例如:

x = 'foo'
y = 'bar'
d = autodict(x, y)
print d

愿意:

{'x': 'foo', 'y': 'bar'}

检查源代码本身比搜索locals()globals() 更好,因为后一种方法不会告诉您哪些变量是您想要的。

无论如何,代码如下:

def autodict(*args):
    get_rid_of = ['autodict(', ',', ')', '\n']
    calling_code = inspect.getouterframes(inspect.currentframe())[1][4][0]
    calling_code = calling_code[calling_code.index('autodict'):]
    for garbage in get_rid_of:
        calling_code = calling_code.replace(garbage, '')
    var_names, var_values = calling_code.split(), args
    dyn_dict = {var_name: var_value for var_name, var_value in
                zip(var_names, var_values)}
    return dyn_dict

该操作发生在inspect.getouterframes 的行中,它返回调用autodict 的代码中的字符串。

这种魔法的明显缺点是它对源代码的结构做出假设。当然,如果它在解释器中运行,它就根本不起作用。

【讨论】:

  • 您好,我只有三个问题: 1. 为什么是“1”? 2. 为什么是“4”? 3. 为什么是“0”? :)
【解决方案11】:

此函数将打印变量名及其值:

import inspect

def print_this(var):
    callers_local_vars = inspect.currentframe().f_back.f_locals.items()
    print(str([k for k, v in callers_local_vars if v is var][0])+': '+str(var))
***Input & Function call:***
my_var = 10

print_this(my_var)

***Output**:*
my_var: 10

【讨论】:

    【解决方案12】:
    >>> locals()['foo']
    {}
    >>> globals()['foo']
    {}
    

    如果您想编写自己的函数,可以这样来检查本地变量中定义的变量,然后检查全局变量。如果没有找到,您可以比较 id() 以查看变量是否指向内存中的相同位置。

    如果您的变量在一个类中,您可以使用 className.dict.keys() 或 vars(self) 来查看您的变量是否已定义。

    【讨论】:

    • 如果名字在调用者框架中怎么办?然后,您将不得不做一些愚蠢的事情,例如遍历堆栈并检查每个人的localsglobals...如果实际上不存在名称,则您可能会弄错名称。这是一项没有实际有用收益的工作。
    • 整个问题都很愚蠢……但如果这是他想做的事情,那是可能的。至于检查存在,你可以使用 Globals().setdefault(var,
    【解决方案13】:

    我有一个方法,虽然不是最有效的...它有效! (而且它不涉及任何花哨的模块)。

    基本上,它会将您的变量 IDglobals() 变量的 ID 进行比较,然后返回匹配的名称。

    def getVariableName(variable, globalVariables=globals().copy()):
        """ Get Variable Name as String by comparing its ID to globals() Variables' IDs
    
            args:
                variable(var): Variable to find name for (Obviously this variable has to exist)
    
            kwargs:
                globalVariables(dict): Copy of the globals() dict (Adding to Kwargs allows this function to work properly when imported from another .py)
        """
        for globalVariable in globalVariables:
            if id(variable) == id(globalVariables[globalVariable]): # If our Variable's ID matches this Global Variable's ID...
                return globalVariable # Return its name from the Globals() dict
    

    【讨论】:

      【解决方案14】:

      在 Python 中,defclass 关键字会将特定名称绑定到它们定义的对象(函数或类)。类似地,模块通过在文件系统中被称为特定的东西而被命名。在所有这三种情况下,都有一种明显的方法可以为相关对象分配“规范”名称。

      但是,对于其他类型的对象,这样的规范名称可能根本不存在。例如,考虑一个列表的元素。列表中的元素没有单独命名,完全有可能在程序中引用它们的唯一方法是使用包含列表上的列表索引。如果将这样的对象列表传递到您的函数中,您就不可能为这些值分配有意义的标识符。

      Python 不会将分配左侧的名称保存到分配的对象中,因为:

      1. 这需要在多个冲突对象中找出哪个名称是“规范的”,
      2. 对于从未分配给显式变量名的对象毫无意义,
      3. 这将是极其低效的,
      4. 实际上没有其他语言可以做到这一点。

      因此,例如,使用 lambda 定义的函数将始终具有“名称”&lt;lambda&gt;,而不是特定的函数名称。

      最好的方法是让调用者传入一个(可选的)姓名列表。如果输入 '...','...' 太麻烦,您可以接受例如包含逗号分隔的名称列表的单个字符串(如 namedtuple 所做的那样)。

      【讨论】:

        【解决方案15】:

        许多答案只返回一个变量名。但是,如果多个变量具有相同的值,那将无法正常工作。这是 Amr Sharaki 答案的变体,如果更多变量具有相同的值,则返回多个结果。

        def getVariableNames(variable):
            results = []
            globalVariables=globals().copy()
            for globalVariable in globalVariables:
                if id(variable) == id(globalVariables[globalVariable]):
                    results.append(globalVariable)
            return results
        
        a = 1
        b = 1
        getVariableNames(a)
        # ['a', 'b']
        

        【讨论】:

          【解决方案16】:

          我认为在 Python 中执行此操作非常困难,因为您永远不会不知道您正在使用的变量的名称。所以,在他的例子中,你可以这样做:

          代替:

          list_of_dicts = [n_jobs, users, queues, priorities]
          
          dict_of_dicts = {"n_jobs" : n_jobs, "users" : users, "queues" : queues, "priorities" : priorities}
          

          【讨论】:

          • 你的第一句话没有意义——还有多余的吗?
          【解决方案17】:

          只是根据输入变量的内容执行此操作的另一种方法:

          (返回与输入变量匹配的第一个变量的名称,否则返回无。可以修改它以获取与输入变量具有相同内容的所有变量名称)

          def retrieve_name(x, Vars=vars()):
              for k in Vars:
                  if isinstance(x, type(Vars[k])):
                      if x is Vars[k]:
                          return k
              return None
          

          【讨论】:

            【解决方案18】:

            如果目标是帮助您跟踪变量,您可以编写一个简单的函数来标记变量并返回其值和类型。例如,假设 i_f=3.01 并将其舍入为一个名为 i_n 的整数以在代码中使用,然后需要一个字符串 i_s 将其放入报告中。

            def whatis(string, x):
                print(string+' value=',repr(x),type(x))
                return string+' value='+repr(x)+repr(type(x))
            i_f=3.01
            i_n=int(i_f)
            i_s=str(i_n)
            i_l=[i_f, i_n, i_s]
            i_u=(i_f, i_n, i_s)
            
            ## make report that identifies all types
            report='\n'+20*'#'+'\nThis is the report:\n'
            report+= whatis('i_f ',i_f)+'\n'
            report+=whatis('i_n ',i_n)+'\n'
            report+=whatis('i_s ',i_s)+'\n'
            report+=whatis('i_l ',i_l)+'\n'
            report+=whatis('i_u ',i_u)+'\n'
            print(report)
            

            这会在每次调用时打印到窗口以进行调试,并且还会为书面报告生成一个字符串。唯一的缺点是每次调用函数时都必须输入两次变量。

            我是一名 Python 新手,发现这种方法非常有用,可以记录我在编程时所做的工作并尝试处理 Python 中的所有对象。一个缺陷是,如果 whatis() 调用在使用它的过程之外描述的函数,它就会失败。例如,int(i_f) 是一个有效的函数调用,只是因为 Python 知道 int 函数。您可以使用 int(i_f**2) 调用 whatis(),但如果出于某种奇怪的原因您选择定义一个名为 int_squared 的函数,则必须在使用 whatis() 的过程中声明它。

            【讨论】:

              【解决方案19】:

              也许这可能有用:

              def Retriever(bar):
                  return (list(globals().keys()))[list(map(lambda x: id(x), list(globals().values()))).index(id(bar))]
              

              该函数从全局范围(可以编辑命名空间)中遍历值的 ID 列表,根据其 ID 找到所需/需要的 var 或函数的索引,然后从列表中返回名称基于获取的索引的全局名称。

              【讨论】:

              • 看起来非常吓人,但它确实有效,而且运行速度非常快。 4.41 us +/- 1.2 us per loop (mean +/- std. dev. of 7 runs, 100000 loops each 仅用于一个变量和函数。随着定义的变量计数的增加,运行时间确实会缓慢增加。 21us 和 103 在 iPython 中定义。可能不适合非常大的环境,但也许有办法优化......?
              • 好的,这似乎有一些缺点。以两个赋值为 0 的变量为例,它们被赋值给一个元组,即t = (var1, var2)。虽然可以使用它来获取分配给元组槽的变量名,但var2 的槽将返回变量名var1。我相信这是因为常量是预先生成的并在内存中分配了一个插槽作为优化技术,因此反向查找将指向分配值的最旧的现有变量。因此,由于不准确的问题,我不建议将其用于大型项目。
              【解决方案20】:

              每当我必须这样做时,主要是在与前端通信 json 模式和常量时,我​​定义一个类如下

              class Param:
                  def __init__(self, name, value):
                      self.name = name
                      self.value = value
              

              然后用名称和值定义变量。

              frame_folder_count = Param({'name':'frame_folder_count', 'value':10})
              

              现在您可以使用对象访问名称和值。

              >>> frame_folder_count.name
              'frame_folder_count'
              

              【讨论】:

              • 我认为这与问题不符。但无论如何我想建议你使用pydantic,它真的很适合这种用法
              • 您的代码没有运行。应该在Param('frame_folder_count', 10)Param(**{'name':'frame_folder_count', 'value':10}) 的行上
              【解决方案21】:
              >>> def varname(v, scope=None):
                      d = globals() if not scope else vars(scope); return [k for k in d if d[k] == v]
              ...
              >>> d1 = {'a': 'ape'}; d2 = {'b': 'bear'}; d3 = {'c': 'cat'}
              >>> ld = [d1, d2, d3]
              >>> [varname(d) for d in ld]
              [['d1'], ['d2'], ['d3']]
              >>> d5 = d3
              >>> [varname(d) for d in ld]
              [['d1'], ['d2'], ['d3', 'd5']]
              >>> def varname(v, scope=None):
                      d = globals() if not scope else vars(scope); return [k for k in d if d[k] is v]
              ...
              >>> [varname(d) for d in ld]
              [['d1'], ['d2'], ['d3', 'd5']]
              

              如您所见,是noted here,可以有多个具有相同值甚至地址的变量,所以using a wrapper最好保留名称与数据。

              【讨论】:

              • 我收到RuntimeError: dictionary changed size during iteration
              • @étale-cohomology 在这里可以正常工作:>>> import sys;sys.version '3.8.5 (tags/v3.8.5:580fbb0, Jul 20 2020, 15:57:54) [MSC v.1924 64 位 (AMD64)]'
              【解决方案22】:

              以下方法不会返回变量的名称,但如果变量在全局范围内可用,则使用此方法可以轻松创建数据框。

              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}
              
              A = [0, 1]
              B = [1, 2]
              pd.DataFrame(G.A + G.B) # It will return a data frame with A and B columns
              

              【讨论】:

                【解决方案23】:

                我尝试从inspect locals 中获取名称,但它无法处理像a[1]、b.val 这样的var。 之后,我有了一个新的想法——从代码中获取var name,我试了一下succ! 代码如下:

                #direct get from called function code
                def retrieve_name_ex(var):
                    stacks = inspect.stack()
                    try:
                        func = stacks[0].function
                        code = stacks[1].code_context[0]
                        s = code.index(func)
                        s = code.index("(", s + len(func)) + 1
                        e = code.index(")", s)
                        return code[s:e].strip()
                    except:
                        return ""
                

                【讨论】:

                  【解决方案24】:

                  您可以尝试以下方法来检索您定义的函数的名称(但不适用于内置函数):

                  import re
                  def retrieve_name(func):
                      return re.match("<function\s+(\w+)\s+at.*", str(func)).group(1)
                  
                  def foo(x):
                      return x**2
                  
                  print(retrieve_name(foo))
                  # foo
                  

                  【讨论】:

                    【解决方案25】:

                    从变量的值中查找变量的名称时,
                    您可能有多个变量等于相同的值,
                    例如 var1 = 'hello' 和 var2 = 'hello'。

                    我的解决方案:

                    def find_var_name(val):
                    
                        dict_list = []
                        global_dict = dict(globals())
                    
                        for k, v in global_dict.items():
                            dict_list.append([k, v])
                       
                        return [item[0] for item in dict_list if item[1] == val]
                    
                    var1 = 'hello'
                    var2 = 'hello'
                    find_var_name('hello')
                    

                    输出

                    ['var1', 'var2']
                    

                    【讨论】:

                      【解决方案26】:

                      iDilip 答案的压缩版:

                      import inspect
                      def varname(x):
                        return [k for k,v in inspect.currentframe().f_back.f_locals.items() if v is x][0]
                      
                      hi = 123
                      print(varname(hi))
                      

                      【讨论】:

                        【解决方案27】:

                        如果有两个具有相同值的变量,前面的一些案例会失败。所以方便提醒一下:

                        定义函数:

                        # Variable to string of variable name
                        
                        def var_name(variable,i=0):
                        
                          results = []
                          for name in globals():   
                             if eval(name) == variable:
                               results.append(name)
                        
                          if len(results) > 1:
                            print('Warning:' )
                            print('   var_name() has found',len(results), 'possible outcomes.')
                            print('   Please choose the suitable parameter "i". Where "i" is the index')
                            print('   that matches your choice from the list below.')
                            print('  ',results) ; print('')
                        
                          return results[i]
                        

                        用途:

                        var_1 = 10
                        var_name(var_1) # Output will be "var_1"
                        

                        如果您有 2 个具有相同值的变量,例如 var_1 = 8var_2 = 8,则会出现警告。

                        var_1 = 8
                        var_2 = 8
                        var_name(var_2)  # Output will be "var_1" too but Warning will appear
                        

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 2010-09-20
                          • 1970-01-01
                          • 2019-08-28
                          • 1970-01-01
                          相关资源
                          最近更新 更多