我想将一个Python变量名转换为字符串形式,如下所示。有什么好主意吗?
var = {}
print ??? # Would like to see 'var'
something_else = 3
print ??? # Would print 'something_else'
有一种使用情境,您可能需要这样做。我并不意味着没有更好的方法或达到相同的功能。
这将非常有用,以便在错误、调试模式和其他类似情况下“转储”任意字典列表。
所需的是 eval()
函数的反向操作:
get_indentifier_name_missing_function()
需要一个以标识符名称('variable','dictionary'等)为参数的函数,并返回包含该标识符名称的字符串。
考虑以下现状:
random_function(argument_data)
如果一个人把标识符名称('function','variable','dictionary'等)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
现在,考虑使用假想的 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_identifier_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) )
######
eval()
函数引用表示标识符名称的字符串才能被引用回实际标识符。eval()
函数,对于在调用代码中未直接“看到”标识符名称的情况将没有用处。例如,在任何已调用的函数内部。可以通过同时传递'string'
和eval('string')
来实现这一点。我认为这是最“通用”的解决方案,可以在任意函数、模块、命名空间中解决这个鸡蛋问题,而不使用边角情况的解决方案。唯一的缺点是使用eval()
函数可能很容易导致不安全的代码。必须注意不要将eval()
函数与几乎任何东西一起使用,特别是未经过滤的外部输入数据。
使用 python-varname 包 (python3) 完全可以实现:
from varname import nameof
s = 'Hey!'
print (nameof(s))
输出:
s
安装:
pip3 install varname
或者在这里获取软件包:
lambda x: var is globals () [x [0]]
测试globals().items()列表中的每个元组进行搜索。在该函数中,x是被测试的元组; x [0]是变量名(作为字符串),x [1]是值。lambda函数测试是否被测试变量的值与传递给variablename()的变量的值相同。实际上,通过使用is
操作符,lambda函数测试被测试变量的名称是否绑定到与传递给variablename()的变量完全相同的对象。如果是,则元组通过测试并由ifilter()返回。[tpl[0] for tpl ... globals().items())]
。列表理解仅保存变量名tpl[0]
,忽略变量值。创建的列表包含一个或多个名称(作为字符串),这些名称绑定到传递给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()
函数提供了相同的功能。
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
因此,对于类,它会提供名称和属性。
is variable
而不是 == variable
... 更安全。 - Erik Aronestyprint name
更改为print(name)
非常明显,但它仍然会出错。@Erik Aronesty的修复方法可以使其正常工作,但@steveha指出的问题仍然存在。 - JC_CL这是不可能的。
在Python中,实际上并不存在所谓的“变量”。Python真正拥有的是可以绑定对象的“名称”。对象无论被绑定到哪个名称上都不会受到影响。它可能被绑定到几十个不同的名称上,也可能没有被绑定到任何名称上。
考虑以下示例:
foo = 1
bar = 1
baz = 1
print foo
打印"foo"
,那么你最好一开始就执行print "foo"
。foo = 1
bar = foo
baz = foo
实际上,Python会重复使用具有常见值(如0或1)的整数对象,因此第一个示例应将相同的对象绑定到所有三个名称。但是这个示例非常清晰:相同的对象绑定到了foo、bar和baz。
从技术上讲,这些信息对您是可用的,但正如其他人所问,您如何以明智的方式利用它呢?
>>> x = 52
>>> globals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__',
'x': 52, '__doc__': None, '__package__': None}
>>> globals().keys()[2]
'x'
>>> for k in globals().keys():
... if not k.startswith("_"):
... print k
...
x
>>>
通过使用解包操作符:
>>> def tostr(**kwargs):
return kwargs
>>> var = {}
>>> something_else = 3
>>> tostr(var = var,something_else=something_else)
{'var' = {},'something_else'=3}
variabletostr(df=0)
`顺便说一下:我将此代码作为新帖子添加到了该线程中。 - Arend我认为这是一个很酷的解决方案,也许是最好的解决方案。但是你有没有想过如何处理你的函数可能返回的模棱两可的结果?正如"is" operator behaves unexpectedly with integers所示,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...
这里有一个简洁的变体,可以让您指定任何目录。 使用目录查找任何内容的问题在于多个变量可能具有相同的值。因此,此代码返回可能变量的列表。
def varname( var, dir=locals()):
return [ key for key, val in dir.items() if id( val) == id( var)]
在有限的范围内是可能的。答案类似于@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']
您可以将此示例扩展到任何其他变量/数据类型
def to_R( py_var ): r.assign( 'py_var', py_var )
将(Py)py_var中的数据分配到R环境中并具有相同的名称。对我来说,做以下操作会很有用,r.assign( py_var.stringof, py_var )
,就像D一样,因为传递给我的fnto_r
的变量名不一定是py_var
。 - Matthew Turner