将变量名称转换为字符串?

2025-03-19 08:57:00
admin
原创
58
摘要:问题描述:我想将 Python 变量名转换为如下所示的字符串。有什么想法吗?var = {} print ??? # Would like to see 'var' something_else = 3 print ??? # Would print 'something_else' 解决方案 1:TL;...

问题描述:

我想将 Python 变量名转换为如下所示的字符串。有什么想法吗?

var = {}
print ???  # Would like to see 'var'
something_else = 3
print ???  # Would print 'something_else'

解决方案 1:

TL;DR:不可能。请参阅最后的“结论”。


有一种使用场景您可能需要它。我并不是说没有更好的方法或实现相同的功能。

这对于在出现错误、调试模式和其他类似情况下“转储”任意字典列表很有用。

所需要的是该eval()函数的逆函数:

get_indentifier_name_missing_function()

它将以标识符名称(“变量”、“字典”等)作为参数,并返回包含该标识符名称的字符串。


考虑以下当前的情况:

random_function(argument_data)

如果将一个标识符名称(“函数”、“变量”、“字典”等)传递argument_datarandom_function()(另一个标识符名称),则实际上是将一个标识符(例如<argument_data object at 0xb1ce10>:)传递给另一个标识符(例如:)<function random_function at 0xafff78>

<function random_function at 0xafff78>(<argument_data object at 0xb1ce10>)

据我了解,只有内存地址被传递给函数:

<function at 0xafff78>(<object at 0xb1ce10>)

因此,需要传递一个字符串作为参数,random_function()以便该函数具有参数的标识符名称:

random_function('argument_data')

random_function() 内部

def random_function(first_argument):

,可以使用已经提供的字符串'argument_data'来:

  1. 用作“标识符名称”(用于显示、记录、字符串拆分/连接等)

  2. 提供给eval()函数以获取对实际标识符的引用,从而获取对真实数据的引用:

print("Currently working on", first_argument)
some_internal_var = eval(first_argument)
print("here comes the data: " + str(some_internal_var))

不幸的是,这并非在所有情况下都有效。只有当random_function()可以将字符串解析'argument_data'为实际标识符时,它才有效。即,如果标识符名称在的命名空间argument_data中可用。random_function()

情况并不总是这样的:

# main1.py
import some_module1

argument_data = 'my data'

some_module1.random_function('argument_data')


# some_module1.py
def random_function(first_argument):
    print("Currently working on", first_argument)
    some_internal_var = eval(first_argument)
    print("here comes the data: " + str(some_internal_var))
######

预期结果如下:

Currently working on: argument_data
here comes the data: my data

因为argument_data标识符名称在 的命名空间中不可用random_function(),所以会产生以下结果:

Currently working on argument_data
Traceback (most recent call last):
  File "~/main1.py", line 6, in <module>
    some_module1.random_function('argument_data')
  File "~/some_module1.py", line 4, in random_function
    some_internal_var = eval(first_argument)
  File "<string>", line 1, in <module>
NameError: name 'argument_data' is not defined

现在,考虑一下 a 的假设用法,get_indentifier_name_missing_function()其行为将如上所述。

这是一个虚拟的 Python 3.0 代码:。

# main2.py
import some_module2
some_dictionary_1       = { 'definition_1':'text_1',
                            'definition_2':'text_2',
                            'etc':'etc.' }
some_other_dictionary_2 = { 'key_3':'value_3',
                            'key_4':'value_4', 
                            'etc':'etc.' }
#
# more such stuff
#
some_other_dictionary_n = { 'random_n':'random_n',
                            'etc':'etc.' }

for each_one_of_my_dictionaries in ( some_dictionary_1,
                                     some_other_dictionary_2,
                                     ...,
                                     some_other_dictionary_n ):
    some_module2.some_function(each_one_of_my_dictionaries)


# some_module2.py
def some_function(a_dictionary_object):
    for _key, _value in a_dictionary_object.items():
        print( get_indentifier_name_missing_function(a_dictionary_object)    +
               "    " +
               str(_key) +
               "  =  " +
               str(_value) )
######

预期结果如下:

some_dictionary_1    definition_1  =  text_1
some_dictionary_1    definition_2  =  text_2
some_dictionary_1    etc  =  etc.
some_other_dictionary_2    key_3  =  value_3
some_other_dictionary_2    key_4  =  value_4
some_other_dictionary_2    etc  =  etc.
......
......
......
some_other_dictionary_n    random_n  =  random_n
some_other_dictionary_n    etc  =  etc.

不幸的是,get_indentifier_name_missing_function()看不到“原始”标识符名称(some_dictionary_some_other_dictionary_2some_other_dictionary_n)。它只会看到a_dictionary_object标识符名称。

因此真正的结果应该是:

a_dictionary_object    definition_1  =  text_1
a_dictionary_object    definition_2  =  text_2
a_dictionary_object    etc  =  etc.
a_dictionary_object    key_3  =  value_3
a_dictionary_object    key_4  =  value_4
a_dictionary_object    etc  =  etc.
......
......
......
a_dictionary_object    random_n  =  random_n
a_dictionary_object    etc  =  etc.

因此,在这种情况下,函数的逆函数eval()不会那么有用。


目前,需要执行以下操作:

# main2.py same as above, except:

    for each_one_of_my_dictionaries_names in ( 'some_dictionary_1',
                                               'some_other_dictionary_2',
                                               '...',
                                               'some_other_dictionary_n' ):
        some_module2.some_function( { each_one_of_my_dictionaries_names :
                                     eval(each_one_of_my_dictionaries_names) } )
    
    
    # some_module2.py
    def some_function(a_dictionary_name_object_container):
        for _dictionary_name, _dictionary_object in a_dictionary_name_object_container.items():
            for _key, _value in _dictionary_object.items():
                print( str(_dictionary_name) +
                       "    " +
                       str(_key) +
                       "  =  " +
                       str(_value) )
    ######

综上所述:

  • Python 仅将内存地址作为参数传递给函数。

  • 表示标识符名称的字符串,仅当eval()名称标识符在当前命名空间中可用时,才能通过函数引用回实际标识符。

  • 如果标识符名称不能被调用代码直接“看到”,那么假设函数的逆向eval()将毫无用处。例如,在任何被调用函数内部。

  • 目前需要传递给一个函数:

    1. 表示标识符名称的字符串

    2. 实际标识符(内存地址)

这可以通过同时将'string'eval('string')传递给被调用函数来实现。我认为这是在任意函数、模块、命名空间中解决这个先有蛋还是先有鸡问题的最“通用”方法,而无需使用极端情况解决方案。唯一的缺点是使用该eval()函数很容易导致不安全的代码。必须注意不要向eval()函数提供任何东西,尤其是未过滤的外部输入数据。

解决方案 2:

使用 python-varname 包(python3)完全可以实现:

from varname import nameof

s = 'Hey!'

print (nameof(s))

输出:

s

安装:

pip3 install varname

或者在这里获取软件包:

https://github.com/pwwang/python-varname

解决方案 3:

只要它是一个变量而不是第二个类,这对我有用:

def print_var_name(variable):
 for name in globals():
     if eval(name) == variable:
        print name
foo = 123
print_var_name(foo)
>>>foo

班级成员会发生这种情况:

class xyz:
     def __init__(self):
         pass
member = xyz()
print_var_name(member)
>>>member

针对类回答这个问题(例如):

abc = xyz
print_var_name(abc)
>>>abc
>>>xyz

因此对于类,它会给你名称和属性

解决方案 4:

我搜索这个问题是因为我想要一个 Python 程序来打印程序中某些变量的赋值语句。例如,它可能会打印“foo = 3, bar = 21, baz = 432”。打印函数需要字符串形式的变量名称。我本可以为我的代码提供字符串“foo”、“bar”和“baz”,但感觉像是在重复自己。在阅读了前面的答案后,我开发了下面的解决方案。

globals() 函数的行为类似于一个字典,以变量名(字符串形式)作为键。我想从 globals() 中检索与每个变量的值相对应的键。方法 globals().items() 返回一个元组列表;在每个元组中,第一项是变量名(字符串形式),第二项是变量值。我的 variablename() 函数搜索该列表以找到与我需要的字符串形式变量值相对应的变量名。

函数 itertools.ifilter() 通过使用函数 测试 globals().items() 列表中的每个元组来进行搜索lambda x: var is globals()[x[0]]。在该函数中,x 是被测试的元组;x[0] 是变量名称(字符串),x[1] 是值。lambda 函数测试被测试变量的值是否与传递给 variablename() 的变量的值相同。实际上,通过使用is运算符,lambda 函数测试被测试变量的名称是否与传递给 variablename() 的变量绑定到完全相同的对象。如果是这样,则元组通过测试并由 ifilter() 返回。

itertools.ifilter() 函数实际上返回一个迭代器,该迭代器在正确调用之前不会返回任何结果。为了正确调用它,我将其放在列表推导式中[tpl[0] for tpl ... globals().items())]。列表推导式仅保存变量名称tpl[0],而忽略变量值。创建的列表包含一个或多个名称(作为字符串),这些名称与传递给 variablename() 的变量的值绑定在一起。

在下面显示的 variablename() 用法中,所需的字符串作为列表中的元素返回。在许多情况下,它将是列表中的唯一项目。但是,如果另一个变量名被赋予相同的值,则列表将会更长。

>>> def variablename(var):
...     import itertools
...     return [tpl[0] for tpl in 
...     itertools.ifilter(lambda x: var is x[1], globals().items())]
... 
>>> var = {}
>>> variablename(var)
['var']
>>> something_else = 3
>>> variablename(something_else)
['something_else']
>>> yet_another = 3
>>> variablename(something_else)
['yet_another', 'something_else']

itertools.ifilter()在 Python 3 中被删除,因为内置filter()函数现在提供了相同的功能。

解决方案 5:

这是不可能的。

在 Python 中,实际上不存在“变量”这样的东西。Python 真正拥有的是可以绑定对象的“名称”。对象绑定到什么名称(如果有的话)对它来说没有区别。它可能绑定到几十个不同的名称,也可能没有。

考虑这个例子:

foo = 1
bar = 1
baz = 1

现在,假设您有一个值为 1 的整数对象,并且您想反向查找其名称。您会打印什么?三个不同的名称都与该对象绑定,并且它们都同样有效。

在 Python 中,名称是访问对象的一种方式,因此无法直接使用名称。也许有一些巧妙的方法可以破解 Python 字节码或其他东西来获取名称的值,但这充其量只是一种小把戏。

如果您知道您想要print foo打印"foo",那么您最好print "foo"首先执行。

编辑:我稍微修改了措辞,使其更清楚。此外,这是一个更好的例子:

foo = 1
bar = foo
baz = foo

实际上,Python 会将同一个对象重用于具有 0 或 1 等常见值的整数,因此第一个例子应该将同一个对象绑定到所有三个名称。但这个例子非常清楚:同一个对象绑定到 foo、bar 和 baz。

解决方案 6:

从技术上讲,您可以获取这些信息,但正如其他人所问的那样,您将如何合理地利用这些信息?

>>> x = 52
>>> globals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', 
'x': 52, '__doc__': None, '__package__': None}

这表明变量名作为字符串存在于 globals() 字典中。

>>> globals().keys()[2]
'x'

在这种情况下,它恰好是第三个键,但没有可靠的方法知道给定的变量名最终会出现在哪里

>>> for k in globals().keys():
...   if not k.startswith("_"):
...     print k
...
x
>>>

您可以像这样过滤掉系统变量,但您仍将获得所有您自己的项目。只需运行上述代码即可创建另一个变量“k”,该变量会更改字典中“x”的位置。

但也许这对您来说是一个有用的开始。如果您告诉我们您想要此功能的用途,我们可能会提供更多有用的信息。

解决方案 7:

适用于 Python >= 3.8(带有 f'{var=}' 字符串)

不确定这是否可以在生产代码中使用,但在 Python 3.8(及更高版本)中,您可以使用 f' 字符串调试说明符。在表达式末尾添加 =,它将打印表达式及其值:

my_salary_variable = 5000
print(f'{my_salary_variable  =  }')

Output:
my_salary_variable  =  5000

为了揭示这个魔力,下面是另一个例子:

param_list = f'{my_salary_variable=}'.split('=')
print(param_list)

Output:
['my_salary_variable', '5000']

解释:当您在 f'string 中的变量后面放置 '=' 时,它将返回一个包含变量名、'=' 及其值的字符串。使用 .split('=') 将其拆分并获取一个包含 2 个字符串的列表,[0] - 变量名,[1] - 变量的实际对象。
如果您只需要变量名,则选择列表中的 [0] 元素。

my_salary_variable = 5000
param_list = f'{my_salary_variable=}'.split('=')
print(param_list[0])
Output:
my_salary_variable

or, in one line

my_salary_variable = 5000
print(f'{my_salary_variable=}'.split('=')[0])
Output:
my_salary_variable

也可以使用函数:

def my_super_calc_foo(number):
    return number**3

print(f'{my_super_calc_foo(5)  =  }')
print(f'{my_super_calc_foo(5)=}'.split('='))

输出:

my_super_calc_foo(5)  =  125
['my_super_calc_foo(5)', '125']

Process finished with exit code 0

解决方案 8:

你想达到什么目的?绝对没有理由去做你所描述的事情,而且你试图解决的问题可能有更好的解决方案。

您所要求的最明显的替代方案是一本字典。例如:

>>> my_data = {'var': 'something'}
>>> my_data['something_else'] = 'something'
>>> print my_data.keys()
['var', 'something_else']
>>> print my_data['var']
something

主要是作为..挑战,我实现了您想要的输出。请不要使用此代码!

#!/usr/bin/env python2.6
class NewLocals:
    """Please don't ever use this code.."""
    def __init__(self, initial_locals):
        self.prev_locals = list(initial_locals.keys())

    def show_new(self, new_locals):
        output = ", ".join(list(set(new_locals) - set(self.prev_locals)))
        self.prev_locals = list(new_locals.keys())
        return output
# Set up
eww = None
eww = NewLocals(locals())

# "Working" requested code

var = {}

print eww.show_new(locals())  # Outputs: var

something_else = 3
print eww.show_new(locals()) # Outputs: something_else

# Further testing

another_variable = 4
and_a_final_one = 5

print eww.show_new(locals()) # Outputs: another_variable, and_a_final_one

解决方案 9:

通过使用解包运算符

>>> def tostr(**kwargs):
    return kwargs

>>> var = {}
>>> something_else = 3
>>> tostr(var = var,something_else=something_else)
{'var' = {},'something_else'=3}

解决方案 10:

您必须以某种方式引用要打印其名称的变量。因此它看起来像:

print varname(something_else)

没有这样的函数,但如果有的话,那也没什么意义。你必须输入 out something_else,所以你也可以在它的左右两侧输入引号来将名称打印为字符串:

print "something_else"

解决方案 11:

Django 在生成字段名称时不这样做吗?

http://docs.djangoproject.com/en/dev//topics/db/models/#verbose-field-names

我觉得这合理。

解决方案 12:

我认为这是一个很酷的解决方案,我想这是你能得到的最好的解决方案。但是,你有没有看到任何方法来处理你的函数可能返回的模棱两可的结果?正如“is”运算符对整数的行为出乎意料所示,低整数和相同值的字符串会被 python 缓存,因此你的变量名函数可能会以很高的概率提供模棱两可的结果。就我而言,我想创建一个装饰器,通过我传递给它的变量名向类添加一个新变量:

def inject(klass, dependency):
klass.__dict__["__"+variablename(dependency)]=dependency

但是如果你的方法返回模糊的结果,我怎么知道我添加的变量的名称?

var any_var="myvarcontent"
var myvar="myvarcontent"
@inject(myvar)
class myclasss():
    def myclass_method(self):
        print self.__myvar    #I can not be sure, that this variable will be set...

也许如果我还检查本地列表,我至少可以从列表中删除“依赖”变量,但这不是一个可靠的结果。

解决方案 13:

这是一个简洁的变体,允许您指定任何目录。使用目录查找任何内容的问题是多个变量可能具有相同的值。因此此代码返回可能的变量列表。

def varname( var, dir=locals()):
  return [ key for key, val in dir.items() if id( val) == id( var)]

解决方案 14:

我不知道这样做对不对,但对我来说很有效

def varname(variable):
    for name in list(globals().keys()):
        expression = f'id({name})'
        if id(variable) == eval(expression):
            return name

解决方案 15:

在有限的范围内是可能的。答案与@tamtam 的解决方案类似。给定的示例假设以下假设 -

  • 您正在按其值搜索变量

  • 该变量具有独特的值

  • 该值位于全局命名空间中

例子:

testVar         = "unique value"
varNameAsString = [k for k,v in globals().items() if v == "unique value"]
#
# the variable "varNameAsString" will contain all the variable name that matches
# the value "unique value"
# for this example, it will be a list of a single entry "testVar"
#
print(varNameAsString)

输出:['testVar']

您可以将此示例扩展为任何其他变量/数据类型

解决方案 16:

我想指出一个这不是反模式的用例,并且没有更好的方法可以做到这一点。

这似乎是Python 中缺少的一个功能。

有许多函数,例如patch.object,采用要修补或访问的方法或属性的名称。

考虑一下:

patch.object(obj, "method_name", new_reg)

当您更改方法名称时,这可能会引发“错误成功”。例如:您可能会发送错误,而您认为您正在测试……仅仅是因为方法名称重构不当。

现在考虑: varname。这可能是一个高效的内置函数。但现在它可以通过迭代对象或调用者的框架来工作:

现在你的呼叫可以是:

patch.member(obj, obj.method_name, new_reg)

patch 函数可以调用:

varname(var, obj=obj)

这将:断言 var 已绑定到 obj 并返回成员的名称。或者,如果未指定 obj,则使用调用者堆栈框架来派生它,等等。

在某些时候可以将其设为高效的内置功能,但这里有一个可行的定义。我故意不支持内置功能,但很容易添加:

您可以随意将它粘贴到名为的包中varname.py,并在 patch.object 调用中使用它:

patch.object(obj, varname(obj, obj.method_name), new_reg)

注意:这是为 Python 3 编写的。

import inspect

def _varname_dict(var, dct):
    key_name = None
    for key, val in dct.items():
        if val is var:
            if key_name is not None:
                raise NotImplementedError("Duplicate names not supported %s, %s" % (key_name, key))
            key_name = key
    return key_name

def _varname_obj(var, obj):
    key_name = None
    for key in dir(obj):
        val = getattr(obj, key)
        equal = val is var
        if equal:
            if key_name is not None:
                raise NotImplementedError("Duplicate names not supported %s, %s" % (key_name, key))
            key_name = key
    return key_name

def varname(var, obj=None):
    if obj is None:
        if hasattr(var, "__self__"):
            return var.__name__
        caller_frame = inspect.currentframe().f_back
        try:
            ret = _varname_dict(var, caller_frame.f_locals)
        except NameError:
            ret = _varname_dict(var, caller_frame.f_globals)
    else:
        ret = _varname_obj(var, obj)
    if ret is None:
        raise NameError("Name not found. (Note: builtins not supported)")
    return ret

解决方案 17:

这适用于简单数据类型(str、int、float、list 等)。

>>> def my_print(var_str) :
      print var_str+':', globals()[var_str]
>>> a = 5
>>> b = ['你好', ',世界!']
>>> my_print('a')
答:5
>>> my_print('b')
b:['你好',',世界!']

解决方案 18:

它不太像 Python,但我很好奇,找到了这个解决方案。您需要复制全局字典,因为一旦定义新变量,它的大小就会改变。

def var_to_name(var):
    # noinspection PyTypeChecker
    dict_vars = dict(globals().items())

    var_string = None

    for name in dict_vars.keys():
        if dict_vars[name] is var:
            var_string = name
            break

    return var_string


if __name__ == "__main__":
    test = 3
    print(f"test = {test}")
    print(f"variable name: {var_to_name(test)}")

返回:

test = 3
variable name: test

解决方案 19:

var要获取字符串形式的变量名称:

var = 1000
var_name = [k for k,v in locals().items() if v == var][0] 
print(var_name) # ---> outputs 'var'

解决方案 20:

谢谢@restrepo,这正是我创建标准 save_df_to_file() 函数所需要的。为此,我对你的 tostr() 函数做了一些小改动。希望这对其他人有所帮助:

def variabletostr(**df):
        variablename = list(df.keys())[0]
        return variablename
    
    variabletostr(df=0)

解决方案 21:

原始问题已经很老了,但是我找到了一个几乎可以用于 Python 3 的解决方案。(我说几乎是因为我认为你可以接近解决方案,但我不相信有一个足够具体的解决方案可以满足确切的要求)。

首先,您可能需要考虑以下事项:

  • 对象是 Python 中的一个核心概念,它们可以被分配一个变量,但变量本身是一个绑定名称(想想指针或引用)而不是对象本身

  • var只是一个绑定到对象的变量名,并且该对象可以有多个引用(在您的示例中似乎没有)

  • 在这种情况下,var似乎在全局命名空间中,因此您可以使用全局builtin命名global

  • 对同一对象的不同名称引用将共享相同的内容,id 可以通过运行 id 进行检查,builtin id如下所示:id(var)

此函数抓取全局变量并过滤掉与变量内容匹配的变量。

def get_bound_names(target_variable):
    '''Returns a list of bound object names.'''
    return [k for k, v in globals().items() if v is target_variable]

这里真正的挑战是,您不能保证自己就能取回变量名。它将是一个列表,但该列表将包含您要查找的变量名。如果您的目标变量(绑定到对象)实际上是唯一的绑定名称,您可以通过以下方式访问它:

bound_names = get_variable_names(target_variable)
var_string = bound_names[0]

解决方案 22:

该模块用于将变量名称转换为字符串:
https://pypi.org/project/varname/

使用方式如下:

from varname import nameof

variable=0

name=nameof(variable)

print(name)

//output: variable

通过以下方式安装:

pip install varname

解决方案 23:

print "var"
print "something_else"

或者您有其他的意思?

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2482  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1533  
  PLM(产品生命周期管理)项目对于企业优化产品研发流程、提升产品质量以及增强市场竞争力具有至关重要的意义。然而,在项目推进过程中,范围蔓延是一个常见且棘手的问题,它可能导致项目进度延迟、成本超支以及质量下降等一系列不良后果。因此,有效避免PLM项目范围蔓延成为项目成功的关键因素之一。以下将详细阐述三大管控策略,助力企业...
plm系统   0  
  PLM(产品生命周期管理)项目管理在企业产品研发与管理过程中扮演着至关重要的角色。随着市场竞争的加剧和产品复杂度的提升,PLM项目面临着诸多风险。准确量化风险优先级并采取有效措施应对,是确保项目成功的关键。五维评估矩阵作为一种有效的风险评估工具,能帮助项目管理者全面、系统地评估风险,为决策提供有力支持。五维评估矩阵概述...
免费plm软件   0  
  引言PLM(产品生命周期管理)开发流程对于企业产品的全生命周期管控至关重要。它涵盖了从产品概念设计到退役的各个阶段,直接影响着产品质量、开发周期以及企业的市场竞争力。在当今快速发展的科技环境下,客户对产品质量的要求日益提高,市场竞争也愈发激烈,这就使得优化PLM开发流程成为企业的必然选择。缺陷管理工具和六西格玛方法作为...
plm产品全生命周期管理   0  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用