将变量名称转换为字符串?
- 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;DR:不可能。请参阅最后的“结论”。
有一种使用场景您可能需要它。我并不是说没有更好的方法或实现相同的功能。
这对于在出现错误、调试模式和其他类似情况下“转储”任意字典列表很有用。
所需要的是该eval()
函数的逆函数:
get_indentifier_name_missing_function()
它将以标识符名称(“变量”、“字典”等)作为参数,并返回包含该标识符名称的字符串。
考虑以下当前的情况:
random_function(argument_data)
如果将一个标识符名称(“函数”、“变量”、“字典”等)传递argument_data
给random_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'
来:
用作“标识符名称”(用于显示、记录、字符串拆分/连接等)
提供给
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_2
,some_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()
将毫无用处。例如,在任何被调用函数内部。目前需要传递给一个函数:
表示标识符名称的字符串
实际标识符(内存地址)
这可以通过同时将'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"
或者您有其他的意思?
扫码咨询,免费领取项目管理大礼包!