将变量名转换为字符串?


76

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

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

1
您能详细说明您要达到的目标吗?似乎您在问如何以错误的方式解决问题。另外,还有一个类似的问题,但是关于Ruby stackoverflow.com/questions/58482/ruby-get-a-variables-name
dbr

1
我检查了这个问题,因为我想使用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 )一拉d,因为传递给我的FN变量名to_r不一定py_var
马修·特纳

4
一种使用此方法的方法是Assert语句失败时。您可以为用户提供有问题的确切变量名,同时保持代码的通用性,例如AssertionError:'something_else'必须是大于5的数字。然后可以测试每个需要大于5的变量,并获取变量名。在AssertionError消息中。
nu珠穆朗玛峰

Answers:


50

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'执行以下操作:

  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()函数提供几乎任何东西,尤其是未经过滤的外部输入数据。


3
这是一篇出色的文章,也是我来这里寻求的高质量内容。
布伦丹

4
如果要获取对象的名称,在Python中有些不对劲,我们需要在StackOverflow上获得5页的答案。:/
Seymour

1
tl; dr会很好。
尼米兹

@ Nimitz14包含TL; DR。随意提出修改,更正。
Petru Zaharia

TLDR指出无法实现OP的要求。但是,@ Alice的答案以及其他建议使用locals()或globals()的类似答案可以实现这一目标。因此,该TLDR具有误导性,不应作为公认的答案。
罗比克

13

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

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

itertools.ifilter()函数通过使用函数测试globals()。items()列表中的每个元组来进行搜索lambda x: var is globals()[x[0]]。在该函数中,x是要测试的元组;x [0]是变量名(作为字符串),x [1]是值。lambda函数测试被测变量的值是否与传递给variablename()的变量的值相同。实际上,islambda函数通过使用运算符来测试所测试变量的名称是否与传递给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']

8

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

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

因此,对于班级,它会为您提供名称和属性


编辑您的帖子以解决格式问题。很难理解你在说什么。
yhw42

5
阅读能够回答问题而又不问为什么要提出问题的帖子,这真是一种荣幸。
user5920660

1
请注意,可能有相同的值绑定到多个名称。在这种情况下,上面的代码将打印多个名称。没有办法知道哪个名称是“正确的”名称。
steveha

7

从技术上讲,您可以使用这些信息,但是正如其他人所问的那样,您将如何以明智的方式利用它?

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

但这也许对您来说是一个有用的开始。如果您告诉我们您希望此功能做什么,则可能会提供更多有用的信息。


3
克里斯,您的评论似乎与我的回答或原始问题无关。你在骂谁,为什么?您不知道他是在编写生产代码还是只是为了自己的学习而尝试语言功能。
托德(Todd)

7

这不可能。

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


4
对象没有名称,名称有对象
John La Rooy

有一种使用这些名称(globals()dict)的方法,但尚不清楚如何使用该名称来执行OP要求的操作。
托德(Todd)

当然有可能。而且在这方面微不足道(无论如何,它解决了OP的问题)。这只是没人想做的事情。
SilentGhost

你说不可能。还有可能。查看其他答案。@SilentGhost:您能否阐明为什么“没有人应该这样做”?我想这取决于应用程序。你在说什么
罗比克

@Robyc您说“还可以。” 好的。我给出了绑定示例foo barbaz所有示例都包含在内1。那……的“名字”是1什么?如果查看所有全局变量,则可以返回变量名列表:(['foo', 'bar', 'baz']以某种随机顺序)。好的。该列表的用途是什么?名称之一是“真”名称1吗?(不。)我们中那些不可能说“它”的人都同意,您可以浏览全局变量并找到所有名称。我们只是认为这不是一件有用的事情。就像我说的:一个对象“可能绑定到数十个不同的名称,或者没有。”
steveha

3

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

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

2

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

print varname(something_else)

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

print "something_else"

1
这应该是评论,而不是答案。
史蒂夫

2

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

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

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

这很酷,但是非常自动化。感谢您的提示=]
布兰登·佩尔弗里

“绝对没有理由去做您所描述的事情”-我们在这里拥有当地的全知实体。实际上,有一些很好的用例。
MatrixTheatrics


2

我认为这是一个不错的解决方案,我想您将获得最好的解决方案。但是,您是否看到任何处理歧义结果的方法,您的函数可能会返回?由于“ is”运算符在整数显示中表现异常,低整数和相同值的字符串将被python缓存,因此您的variablename-function可能会以很高的可能性优先处理大量结果。就我而言,我想创建一个装饰器,该装饰器通过我通过varialbename将新变量添加到类中:

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

也许如果我还要检查本地列表,我至少可以从列表中删除“ dependency” -Variable,但这将不是一个可靠的结果。


0

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

>>> def my_print(var_str): 
      打印var_str +':',globals()[var_str]
>>> a = 5
>>> b = ['hello',',world!']
>>> my_print('a')
a:5
>>> my_print('b')
b:['hello',',world!']

0

它不是很像Python风格,但是我很好奇,发现了这个解决方案。您需要复制globals词典,因为一旦定义新变量,它的大小就会改变。

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。尽管答案是好的,但我认为由于提供了类似的解决方案,因此您应该对此表示反对,并避免重复。
razdi

0

通过使用拆包运算符

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

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

0

我不知道对与错,但是对我有用

def varname(variable):
    names = []
    for name in list(globals().keys()):
        string = f'id({name})'
        if id(variable) == eval(string):
            names.append(name)
    return names[0]  

0

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.