将变量名转换为字符串?

Posted

技术标签:

【中文标题】将变量名转换为字符串?【英文标题】:Convert Variable Name to String? 【发布时间】:2010-12-04 19:19:38 【问题描述】:

我想将 python 变量名称转换为等效的字符串,如图所示。有什么想法吗?

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

【问题讨论】:

您能否详细说明您想要实现的目标?似乎您在问如何以错误的方式解决问题。此外,还有一个类似的问题,但关于 Ruby ***.com/questions/58482/ruby-get-a-variables-name 我检查了这个问题,因为使用 RPy2,我想传递一个带有同名 R 名称的 Python 变量。一个无用的(但接近我的应用程序)示例:def to_R( py_var ): r.assign( 'py_var', py_var ) 将 (Py) py_var 中的数据分配给 R 环境并具有相同的名称。这样做对我很有用,r.assign( py_var.stringof, py_var ) a la D 因为传递给我的 fn to_r 的变量名不一定是 py_var 使用它的一种方法是当 Assert 语句失败时。您可以为用户提供有问题的确切变量名称,同时保持代码通用,例如AssertionError: 'something_else' 必须是大于 5 的数字。然后您可以测试每个需要大于 5 的变量,并在 AssertionError 消息中获取变量名称。 【参考方案1】:
print "var"
print "something_else"

或者你的意思是什么_else?

【讨论】:

【参考方案2】:

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

print varname(something_else)

没有这样的功能,但如果有,那将毫无意义。您必须输入something_else,因此您也可以在其左右输入引号以将名称打印为字符串:

print "something_else"

【讨论】:

这应该是评论,而不是答案。 我在下面创建了一个varname 函数。也适用于方法。 这是错误的。我想在循环中检查变量的名称!所以,我不能打字,也不是没有意义!【参考方案3】:

这是不可能的。

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

【讨论】:

对象没有名字,名字有对象 有一种方法可以使用这些名称,即 globals() 字典,但尚不清楚如何使用它来完成 OP 要求的操作。 当然,有可能。并且非常微不足道(无论如何它解决了OP的问题)。这只是没有人应该想做的事情。 你说不可能。还是有可能的。查看其他答案。 @SilentGhost:您能否澄清一下为什么“没有人应该这样做”?我想这取决于应用程序。你的论点是什么? @Robyc 你说“还有可能”。好的。我给出了将foo barbaz 全部绑定到1 的示例。那么1 的“名字”是什么?如果您查看所有全局变量,您可以返回变量名称列表:['foo', 'bar', 'baz'](以某种随机顺序)。好的。这个清单有什么用?其中一个名称是1 的“真实”名称吗? (不。)我们这些说“它”的人不可能都同意您可以查看全局变量并找到所有名称;我们只是不认为这是一件有用的事情。正如我所说:一个对象“可能绑定到几十个不同的名称,或者没有。”【参考方案4】:

从技术上讲,您可以使用这些信息,但正如其他人所问的,您将如何以合理的方式使用它?

>>> 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”在字典中的位置。

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

【讨论】:

克里斯,您的评论似乎与我的回答或原始问题无关。你在骂谁,为什么?你不知道他是在编写生产代码还是只是为了自己的教育而尝试语言功能。【参考方案5】:

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

您要求的最明显的替代方法是字典。例如:

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

【讨论】:

这很酷,但就像我想要的那样自动。感谢您的提示 =] “绝对没有理由做你所描述的事情” - 我们在这里有一个本地无所不知的实体。实际上有一些很好的用例。【参考方案6】:

TL;DR:不可能。见最后的“结论”。


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

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

需要的是 eval() 函数的反函数:

get_indentifier_name_missing_function()

将标识符名称('变量','字典'等)作为参数,并返回一个 包含标识符名称的字符串。


考虑以下现状:

random_function(argument_data)

如果将标识符名称('function'、'variable'、'dictionary'等)argument_data 传递给random_function()(另一个标识符名称),则实际上传递一个标识符(例如:&lt;argument_data object at 0xb1ce10&gt; ) 到另一个标识符(例如:&lt;function random_function at 0xafff78&gt;):

<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' 字符串解析为实际标识符时才有效。 IE。如果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_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() 函数的假设反转在调用代码未直接“看到”标识符名称的情况下将没有用。例如。在任何被调用的函数中。 目前需要传递给一个函数:
    代表标识符名称的字符串 实际标识符(内存地址)

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

【讨论】:

这是一篇出色的文章,也是我来这里寻找的优质内容。 如果要获取对象的名称,我们需要在 *** 上获得 5 页的答案,这在 Python 中有些不对劲。 :// 一个 tl;dr 会很好。 TLDR 声明无法实现 OP 的要求。然而,@Alice 的答案和建议使用 locals() 或 globals() 的其他类似答案正是实现了这一点。所以这个 TLDR 具有误导性,这不应该是公认的答案。 有许多语言可以提供这种功能——即使是编译成机器语言的 C/C++ 也可以通过定义; Python 以易于使用的编程入口点而自豪,但缺乏如此流行的工具供人们学习和查看他们的程序在做什么;像 C/C++ 一样,“编译时”函数可以完美地完成这项工作,但似乎所有建议的尝试在 globals() 等中定位变量名的方法都只是部分成功,不能 100% 地工作。匹配是在多个变量可以引用的对象上完成的。【参考方案7】:

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

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

在我看来是合理的。

【讨论】:

我认为在 django 模型中,字段是一个类或实例的属性,获取属性名称与将变量名称转换为字符串不同。【参考方案8】:

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

>>> def my_print(var_str) : 打印 var_str+':', globals()[var_str] >>> a = 5 >>> b = ['你好',',世界!'] >>> my_print('a') 一个:5 >>> my_print('b') b:['你好',',世界!']

【讨论】:

【参考方案9】:

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

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

函数 itertools.ifilter() 通过使用函数 lambda x: var is globals()[x[0]] 测试 globals().items() 列表中的每个元组来进行搜索。在那个函数中 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']

【讨论】:

【参考方案10】:

我认为这是一个很酷的解决方案,我想你能得到最好的解决方案。但是您是否看到任何处理模棱两可的结果的方法,您的函数可能会返回? 正如"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...

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

【讨论】:

【参考方案11】:

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

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

an this for classes(例如):

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

所以对于类,它会为您提供名称和属性

【讨论】:

请edit您的帖子格式问题。很难理解你在说什么。 很高兴阅读一篇回答问题的帖子,而不是抱怨为什么要问这个问题。 请注意,可以将相同的值绑定到多个名称。在这种情况下,上面的代码将打印多个名称。没有办法知道哪个名字是“正确的”。 使用is variable 而不是== variable ...更安全 不幸的是,这似乎不再适用于 python 3。将print name 更改为print(name) 非常明显,但仍然会出错。 @Erik Aronesty 的修复让它工作了,但@steveha 指出的问题仍然存在。【参考方案12】:

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

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

【讨论】:

【参考方案13】:

这不是很 Pythonesque,但我很好奇并找到了这个解决方案。您需要复制全局字典,因为它的大小会在您定义新变量后立即更改。

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

【讨论】:

您正在查找 globals 字典。这个确切的事情已经在之前的答案中完成,没有创建额外的变量并使用itertools。虽然答案很好,但我认为既然提供了类似的解决方案,您应该对此表示赞同并避免重复。【参考方案14】:

通过使用解包操作符

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

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

【讨论】:

感谢@restrepo,这正是我创建标准 save_df_to_file() 函数所需要的。为此,我对您的 tostr() 函数进行了一些小改动:` def variabletostr(**df): variablename = list(df.keys())[0] return variablename variabletostr(df=0) ` FYI: I added此代码作为此线程中的新帖子【参考方案15】:

我不知道它是否正确,但它对我有用

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

【讨论】:

【参考方案16】:

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

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

【讨论】:

【参考方案17】:

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

这似乎是python中的一个缺失功能。

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

考虑一下:

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

当您更改方法的名称时,这可能会启动“假成功”。 IE:你可以发布一个错误,你以为你正在测试......仅仅是因为一个糟糕的方法名称重构。

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

现在你的电话可以是:

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

并且补丁函数可以调用:

varname(var, obj=obj)

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

在某些时候可以成为一个高效的内置函数,但这里有一个有效的定义。我故意不支持builtins,很容易添加:

请随意将其粘贴到名为 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

【讨论】:

【参考方案18】:

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

from varname import nameof

s = 'Hey!'

print (nameof(s))

输出:

s

在这里获取包:

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

【讨论】:

【参考方案19】:

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

像这样使用它:

从变量名导入名称

变量=0

name=nameof(变量)

打印(名称)

//输出:变量

通过以下方式安装它:

pip 安装变量名

【讨论】:

这个包已经提到here。 (顺便说一句:!pip 之前不正确)。 是的,我注意到它在发布后已经被提及。你是对的'!',我编辑了它。之所以这样,是因为我在笔记本上,如果您在 Jupyter 上,请仅使用“!”。【参考方案20】:

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

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

【讨论】:

以上是关于将变量名转换为字符串?的主要内容,如果未能解决你的问题,请参考以下文章

EXCEL VBA 里面如何动态获取字符串转换为变量名?

在 C++ 中将变量名转换为字符串

R语言 - 字符串与变量的转换

JavaScript字符串转换为变量名

如何在 python 中将字符串转换为有效的变量名?

destring — 将字符串变量转换为数字变量,反之亦然