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

时间:2009-10-07 22:06:13

标签: python string variables

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

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

19 个答案:

答案 0 :(得分:36)

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

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

需要什么,与eval()函数相反:

get_indentifier_name_missing_function()

将标识符名称('variable','dictionary'等)作为参数,并返回a 包含标识符名称的字符串。


考虑以下当前事态:

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'来:

  1. 用作'标识符名称'(显示,记录,字符串拆分/连接,等等)
  2. 提供eval()函数以获取对实际标识符的引用,因此引用实际数据:

    print("Currently working on", first_argument)
    some_internal_var = eval(first_argument)
    print("here comes the data: " + str(some_internal_var))
    
  3. 不幸的是,这并不适用于所有情况。仅当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_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. 的字符串
      3. 实际标识符(内存地址)

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

答案 1 :(得分:9)

这是不可能的。

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

答案 2 :(得分:8)

我搜索了这个问题,因为我想要一个Python程序来打印程序中某些变量的赋值语句。例如,它可能会打印“foo = 3,bar = 21,baz = 432”。 print函数需要字符串形式的变量名。我可以用字符串“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']

答案 3 :(得分: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”,它改变了dict中“x”的位置。

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

答案 4 :(得分:4)

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

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

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

答案 5 :(得分:3)

你不得不引用你想要打印名称的变量。所以它看起来像:

print varname(something_else)

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

print "something_else"

答案 6 :(得分:3)

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

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

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

答案 7 :(得分:2)

我认为这是一个很酷的解决方案,我想你能得到最好的解决方案。但是你看到有什么方法可以处理这些恶劣的结果,你的功能可能会回归吗? 正如"is" operator behaves unexpectedly with integers所示,低整数和具有相同值的字符串会被python缓存,因此您的variablename-function可能会以极高的概率提供ambigous结果。 在我的例子中,我想创建一个装饰器,它通过我传递的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...

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

答案 8 :(得分:2)

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

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

答案 9 :(得分:2)

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

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

对我来说似乎很合理。

答案 10 :(得分:1)

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

from varname import nameof

s = 'Hey!'

print (nameof(s))

输出:

s

从这里获取包裹:

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

答案 11 :(得分:0)

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

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

答案 12 :(得分: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

答案 13 :(得分:0)

使用拆箱操作符

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

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

答案 14 :(得分: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]  

答案 15 :(得分:0)

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

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

答案 16 :(得分:0)

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

这似乎是 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,则使用调用方堆栈帧来派生它,等等。

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

随意将其粘贴在名为 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 :(得分:-1)

print "var"
print "something_else"

或者你的意思是something_else?

答案 18 :(得分:-1)

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

像这样使用它:

from varname import nameof

变量=0

name=nameof(variable)

打印(名称)

//输出:变量

安装方式:

pip install varname