如何将变量名作为字符串获取?

时间:2021-01-07 23:38:22

I would like to be able to get the name of a variable as a string but I don't know if Python has that much introspection capabilities. Something like:

我希望能够得到一个变量的名称作为字符串,但是我不知道Python是否有那么多自省功能。喜欢的东西:

>>> print(my_var.__name__)
'my_var'

I want to do that because I have a bunch of vars I'd like to turn into a dictionary like :

我想这样做,因为我有很多vars我想把它变成字典,比如

bar = True
foo = False
>>> my_dict = dict(bar=bar, foo=foo)
>>> print my_dict 
{'foo': False, 'bar': True}

But I'd like something more automatic than that.

但我想要一些更自动的东西。

Python have locals() and vars(), so I guess there is a way.

Python有local()和vars(),所以我认为有一种方法。

25 个解决方案

#1


27  

Are you trying to do this?

你想这么做吗?

dict( (name,eval(name)) for name in ['some','list','of','vars'] )

Example

例子

>>> some= 1
>>> list= 2
>>> of= 3
>>> vars= 4
>>> dict( (name,eval(name)) for name in ['some','list','of','vars'] )
{'list': 2, 'some': 1, 'vars': 4, 'of': 3}

#2


119  

As unwind said, this isn't really something you do in Python - variables are actually name mappings to objects.

正如unwind所言,这并不是在Python中做的事情——变量实际上是对象的名称映射。

However, here's one way to try and do it:

然而,有一种方法可以尝试:

 >>> a = 1
 >>> for k, v in list(locals().iteritems()):
         if v is a:
             a_as_str = k
 >>> a_as_str
 a
 >>> type(a_as_str)
 'str'

#3


52  

I've wanted to do this quite a lot. This hack is very similar to rlotun's suggestion, but it's a one-liner, which is important to me:

我想做很多事情。这次黑客攻击与rlotun的建议非常相似,但它是一种简单的东西,对我来说很重要:

blah = 1
blah_name = [ k for k,v in locals().iteritems() if v is blah][0]

#4


15  

This is not possible in Python, which really doesn't have "variables". Python has names, and there can be more than one name for the same object.

这在Python中是不可能的,因为它实际上没有“变量”。Python有名称,同一对象可以有多个名称。

#5


14  

This is a hack. It will not work on all Python implementations distributions (in particular, those that do not have traceback.extract_stack.)

这是一个黑客。它不能在所有的Python实现发行版上工作(特别是那些没有traceback.extract_stack的发行版)。

import traceback

def make_dict(*expr):
    (filename,line_number,function_name,text)=traceback.extract_stack()[-2]
    begin=text.find('make_dict(')+len('make_dict(')
    end=text.find(')',begin)
    text=[name.strip() for name in text[begin:end].split(',')]
    return dict(zip(text,expr))

bar=True
foo=False
print(make_dict(bar,foo))
# {'foo': False, 'bar': True}

Note that this hack is fragile:

注意,这种方法是脆弱的:

make_dict(bar,
          foo)

(calling make_dict on 2 lines) will not work.

(用两条线调用make_dict)将不起作用。

Instead of trying to generate the dict out of the values foo and bar, it would be much more Pythonic to generate the dict out of the string variable names 'foo' and 'bar':

与其试图从foo和bar的值生成dict类型,不如从字符串变量name 'foo'和'bar'中生成dict类型:

dict([(name,locals()[name]) for name in ('foo','bar')])

#6


10  

I think my problem will help illustrate why this question is useful, and it may give a bit more insight into how to answer it. I wrote a small function to do a quick inline head check on various variables in my code. Basically, it lists the variable name, data type, size, and other attributes, so I can quickly catch any mistakes I've made. The code is simple:

我认为我的问题将有助于说明为什么这个问题是有用的,它可能会提供更多关于如何回答它的见解。我编写了一个小函数来对代码中的各种变量进行快速内联检查。基本上,它列出了变量名、数据类型、大小和其他属性,因此我可以快速地捕捉到我所犯的错误。代码很简单:

def details(val):
  vn = val.__name__                 #  If such a thing existed
  vs = str(val)
  print("The Value of "+ str(vn) + " is " + vs)
  print("The data type of " + vn + " is " + str(type(val)))

So if you have some complicated dictionary / list / tuple situation, it would be quite helpful to have the interpreter return the variable name you assigned. For instance, here is a weird dictionary:

因此,如果您有一些复杂的字典/列表/元组情况,让解释器返回您分配的变量名将非常有用。例如,这里有一本奇怪的字典:

m = 'abracadabra'
mm=[]    
for n in m:
  mm.append(n)
mydic = {'first':(0,1,2,3,4,5,6),'second':mm,'third':np.arange(0.,10)}



details(mydic)

The Value of mydic is {'second': ['a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a'], 'third': array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.]), 'first': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
The data type of mydic is <type 'dict'>

details(mydic['first'])
The Value of mydic['first'] is (0, 1, 2, 3, 4, 5, 6)]
The data type of mydic['first'] is <type 'list'>

details(mydic.keys())
The Value of mydic.keys() is ['second', 'third', 'first']
The data type of mydic.keys() is <type 'tuple'>

details(mydic['second'][0])
The Value of mydic['second'][0] is a
The data type of mydic['second'][0] is <type 'str'>

I'm not sure if I put this in the right place, but I thought it might help. I hope it does.

我不确定我是否把它放在正确的地方,但我认为它可能会有所帮助。我希望它能。

#7


8  

Just for reference, here is answer using keywords:

仅供参考,以下是使用关键词的回答:

Collect the arguments using the ** specifier in the function’s parameter list; this gives you the keyword arguments as a dictionary.

使用函数参数列表中的**说明符收集参数;这将为您提供关键字参数作为字典。

source

Solution:

>>> def get_var_name(**kwargs): return kwargs.keys()[0]

used like :

使用:

>>> var  = 'this is variable'
>>> get_var_name(var=var)
'var'

original answer: https://*.com/a/19201952/2628312

最初的回答:https://*.com/a/19201952/2628312

#8


7  

I wrote a neat little useful function based on the answer to this question. I'm putting it here in case it's useful.

我根据这个问题的答案写了一个很有用的函数。我把它放在这里以防它有用。

def what(obj, callingLocals=locals()):
    """
    quick function to print name of input and value. 
    If not for the default-Valued callingLocals, the function would always
    get the name as "obj", which is not what I want.    
    """
    for k, v in list(callingLocals.items()):
         if v is obj:
            name = k
    print(name, "=", obj)

usage:

用法:

>> a = 4
>> what(a)
a = 4
>>|

#9


6  

In python 3 this is easy

在python 3中,这很简单

myVariable = 5
for v in locals():
  if id(v) == id("myVariable"):
    print(v, locals()[v])

this will print:

这将打印:

myVariable 5

myVariable 5

#10


5  

I find that if you already have a specific list of values, that the way described by @S. Lotts is the best; however, the way described below works well to get all variables and Classes added throughout the code WITHOUT the need to provide variable name though you can specify them if you want. Code can be extend to exclude Classes.

我发现,如果您已经有了一个特定的值列表,就像@S描述的那样。洛特是最好的;但是,下面描述的方法可以很好地在整个代码中添加所有变量和类,而不需要提供变量名,但是如果需要的话可以指定它们。可以扩展代码以排除类。

import types
import math  # mainly showing that you could import what you will before d

# Everything after this counts
d = dict(globals())

def kv_test(k,v):
    return (k not in d and 
            k not in ['d','args'] and
            type(v) is not types.FunctionType)

def magic_print(*args):
    if len(args) == 0: 
        return {k:v for k,v in globals().iteritems() if kv_test(k,v)}
    else:
        return {k:v for k,v in magic_print().iteritems() if k in args}

if __name__ == '__main__':
    foo = 1
    bar = 2
    baz = 3
    print magic_print()
    print magic_print('foo')
    print magic_print('foo','bar')

Output:

输出:

{'baz': 3, 'foo': 1, 'bar': 2}
{'foo': 1}
{'foo': 1, 'bar': 2}

#11


4  

In reading the thread, I saw an awful lot of friction. It's easy enough to give a bad answer, then let someone give the correct answer. Anyway, here is what I found.

在阅读这条线时,我看到了大量的摩擦。给出一个错误的答案很容易,然后让别人给出正确的答案。总之,这是我发现的。

From: [effbot.org] (http://effbot.org/zone/python-objects.htm#names)

来自:[effbot.org](http://effbot.org/zone/python-objects.htm名称)

The names are a bit different — they’re not really properties of the object, and the object itself doesn't know what it’s called.

名字有点不同——它们不是对象的真正属性,对象本身不知道它叫什么。

An object can have any number of names, or no name at all.

对象可以有任意数量的名称,或者根本没有名称。

Names live in namespaces (such as a module namespace, an instance namespace, a function’s local namespace).

名称存在于名称空间中(例如模块名称空间、实例名称空间、函数的本地名称空间)。

Note: that it says the object itself doesn’t know what it’s called, so that was the clue. Python objects are not self-referential. Then it says, Names live in namespaces. We have this in TCL/TK. So maybe my answer will help (but it did help me)

注意:它说对象本身不知道它叫什么,所以这就是线索。Python对象不是自引用的。然后它说,名称在名称空间中存在。我们在TCL/TK中有这个。也许我的答案会有帮助(但它确实帮助了我)


    jj = 123
    print eval("'" + str(id(jj)) + "'")
    print dir()

166707048
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'jj']

So there is 'jj' at the end of the list.

所以,“jj”在名单的最后。

Rewrite the code as:

重写代码为:


    jj = 123
    print eval("'" + str(id(jj)) + "'")
    for x in dir():
        print id(eval(x))

161922920
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'jj']
3077447796
136515736
3077408320
3077656800
136515736
161922920

This nasty bit of code id's the name of variable/object/whatever-you-pedantics-call-it.

这个讨厌的代码id的名称是变量/对象/无论你怎么称呼它。

So, there it is. The memory address of 'jj' is the same when we look for it directly, as when we do the dictionary look up in global name space. I'm sure you can make a function to do this. Just remember which namespace your variable/object/wypci is in.

所以,就是这样。当我们直接查找jj时,它的内存地址是相同的,就像我们在全局名称空间中查找字典一样。我相信你可以用一个函数来做这个。只需记住变量/对象/wypci所在的名称空间。

QED.

QED。

#12


4  

Python3. Use inspect to capture the calling local namespace then use ideas presented here. Can return more than one answer as has been pointed out.

Python3。使用inspect来捕获调用的本地名称空间,然后使用这里提供的想法。可以返回已指出的多个答案。

def varname(var):
  import inspect
  frame = inspect.currentframe()
  var_id = id(var)
  for name in frame.f_back.f_locals.keys():
    try:
      if id(eval(name)) == var_id:
        return(name)
    except:
      pass

#13


3  

Here's the function I created to read the variable names. It's more general and can be used in different applications:

这是我创建用来读取变量名的函数。它更通用,可用于不同的应用:

def get_variable_name(*variable):
    '''gets string of variable name
    inputs
        variable (str)
    returns
        string
    '''
    if len(variable) != 1:
        raise Exception('len of variables inputed must be 1')
    try:
        return [k for k, v in locals().items() if v is variable[0]][0]
    except:
        return [k for k, v in globals().items() if v is variable[0]][0]

To use it in the specified question:

在指定的问题中使用:

>>> foo = False
>>> bar = True
>>> my_dict = {get_variable_name(foo):foo, 
               get_variable_name(bar):bar}
>>> my_dict
{'bar': True, 'foo': False}

#14


2  

import re
import traceback

pattren = re.compile(r'[\W+\w+]*get_variable_name\((\w+)\)')
def get_variable_name(x):
    return pattren.match( traceback.extract_stack(limit=2)[0][3]) .group(1)

a = 1
b = a
c = b
print get_variable_name(a)
print get_variable_name(b)
print get_variable_name(c)

#15


1  

Most objects don't have a __name__ attribute. (Classes, functions, and modules do; any more builtin types that have one?)

大多数对象都没有__name__属性。(类、函数和模块有;还有其他有内置类型的吗?)

What else would you expect for print(my_var.__name__) other than print("my_var")? Can you simply use the string directly?

除了print(my_var.__name__)之外,您还希望打印什么?你能直接使用字符串吗?

You could "slice" a dict:

你可以“切片”一条法令:

def dict_slice(D, keys, default=None):
  return dict((k, D.get(k, default)) for k in keys)

print dict_slice(locals(), ["foo", "bar"])
# or use set literal syntax if you have a recent enough version:
print dict_slice(locals(), {"foo", "bar"})

Alternatively:

另外:

throw = object()  # sentinel
def dict_slice(D, keys, default=throw):
  def get(k):
    v = D.get(k, throw)
    if v is not throw:
      return v
    if default is throw:
      raise KeyError(k)
    return default
  return dict((k, get(k)) for k in keys)

#16


1  

Well, I encountered the very same need a few days ago and had to get a variable's name which was pointing to the object itself.

几天前,我遇到了同样的问题,我需要得到一个指向对象本身的变量名。

And why was it so necessary?

为什么这么必要呢?

In short I was building a plug-in for Maya. The core plug-in was built using C++ but the GUI is drawn through Python(as its not processor intensive). Since I, as yet, don't know how to return multiple values from the plug-in except the default MStatus, therefore to update a dictionary in Python I had to pass the the name of the variable, pointing to the object implementing the GUI and which contained the dictionary itself, to the plug-in and then use the MGlobal::executePythonCommand() to update the dictionary from the global scope of Maya.

简而言之,我正在为Maya构建一个插件。核心插件是使用c++构建的,但是GUI是通过Python绘制的(因为它不是处理器密集型的)。然而,因为我不知道如何从插件除了返回多个值默认MStatus,因此更新字典在Python中我不得不通过变量的名称,指向对象实现GUI和它包含字典本身,插件,然后使用MGlobal::executePythonCommand()来更新字典从全球玛雅的范围。

To do that what I did was something like:

我所做的是:

import time

class foo(bar):

    def __init__(self):
        super(foo, self).__init__()
        self.time = time.time() #almost guaranteed to be unique on a single computer

    def name(self):
        g = globals()
        for x in g:
            if isinstance(g[x], type(self)):
                if g[x].time == self.time:
                    return x
                    #or you could:
                    #return filter(None,[x if g[x].time == self.time else None for x in g if isinstance(g[x], type(self))])
                    #and return all keys pointing to object itself

I know that it is not the perfect solution in in the globals many keys could be pointing to the same object e.g.:

我知道这不是一个完美的解决方案,在全局中,许多键可以指向同一个对象,例如:

a = foo()
b = a
b.name()
>>>b
or
>>>a

and that the approach isn't thread-safe. Correct me if I am wrong.

而且这种方法不是线程安全的。如果我错了请纠正我。

At least this approach solved my problem by getting the name of any variable in the global scope which pointed to the object itself and pass it over to the plug-in, as argument, for it use internally.

至少,这种方法通过获取全局范围中指向对象本身的任何变量的名称并将其作为参数传递给插件来解决我的问题。

I tried this on int (the primitive integer class) but the problem is that these primitive classes don't get bypassed (please correct the technical terminology used if its wrong). You could re-implement int and then do int = foo but a = 3 will never be an object of foo but of the primitive. To overcome that you have to a = foo(3) to get a.name() to work.

我在int(原始整数类)上尝试过这种方法,但问题是这些原始类不会被绕过(如果错误,请纠正所使用的技术术语)。你可以重新实现int然后做int = foo但a = 3永远不会是foo的对象,而是原语的对象。要克服这个问题,必须使用a = foo(3)才能使a.name()工作。

#17


1  

With python 2.7 and newer there is also dictionary comprehension which makes it a bit shorter. If possible I would use getattr instead eval (eval is evil) like in the top answer. Self can be any object which has the context your a looking at. It can be an object or locals=locals() etc.

在python 2.7和更新版本中,还有字典理解功能,这使它更短一些。如果可能的话,我将使用getattr代替eval (eval是邪恶的),就像上面的答案一样。Self可以是任何有上下文的对象。它可以是对象或局部=局部变量()等。

{name: getattr(self, name) for name in ['some', 'vars', 'here]}

#18


1  

Maybe I'm overthinking this but..

也许我想得太多了…

str_l = next((k for k,v in locals().items() if id(l) == id(v)))


>>> bar = True
>>> foo = False
>>> my_dict=dict(bar=bar, foo=foo)
>>> next((k for k,v in locals().items() if id(bar) == id(v)))
'bar'
>>> next((k for k,v in locals().items() if id(foo) == id(v)))
'foo'
>>> next((k for k,v in locals().items() if id(my_dict) == id(v)))
'my_dict'

#19


1  

I was working on a similar problem. @S.Lott said "If you have the list of variables, what's the point of "discovering" their names?" And my answer is just to see if it could be done and if for some reason you want to sort your variables by type into lists. So anyways, in my research I came came across this thread and my solution is a bit expanded and is based on @rlotun solution. One other thing, @unutbu said, "This idea has merit, but note that if two variable names reference the same value (e.g. True), then an unintended variable name might be returned." In this exercise that was true so I dealt with it by using a list comprehension similar to this for each possibility: isClass = [i for i in isClass if i != 'item']. Without it "item" would show up in each list.

我正在研究一个类似的问题。@。洛特说:“如果你有变量列表,那么“发现”它们的名字有什么意义呢?”我的答案是看看是否可以做到如果出于某种原因你想把变量按类型排序成列表。无论如何,在我的研究中,我遇到了这个线程,我的解决方案是扩展的,基于@rlotun解决方案。另一件事,@unutbu说,“这个想法是有价值的,但是请注意,如果两个变量名引用相同的值(例如,True),那么可能会返回一个意外的变量名。”在这个练习中,这是对的,所以我使用了一个类似于对每一种可能性的列表理解:isClass = [I for I In isClass if I != 'item']。没有它,“项目”就会出现在每个列表中。

__metaclass__ = type

from types import *

class Class_1: pass
class Class_2: pass
list_1 = [1, 2, 3]
list_2 = ['dog', 'cat', 'bird']
tuple_1 = ('one', 'two', 'three')
tuple_2 = (1000, 2000, 3000)
dict_1 = {'one': 1, 'two': 2, 'three': 3}
dict_2 = {'dog': 'collie', 'cat': 'calico', 'bird': 'robin'}
x = 23
y = 29
pie = 3.14159
eee = 2.71828
house = 'single story'
cabin = 'cozy'

isClass = []; isList = []; isTuple = []; isDict = []; isInt = []; isFloat = []; isString = []; other = []

mixedDataTypes = [Class_1, list_1, tuple_1, dict_1, x, pie, house, Class_2, list_2, tuple_2, dict_2, y, eee, cabin]

print '\nMIXED_DATA_TYPES total count:', len(mixedDataTypes)

for item in mixedDataTypes:
    try:
        # if isinstance(item, ClassType): # use this for old class types (before 3.0)
        if isinstance(item, type):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isClass.append(mapping_as_str)
            isClass = [i for i in isClass if i != 'item']

        elif isinstance(item, ListType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isList.append(mapping_as_str)
            isList = [i for i in isList if i != 'item']

        elif isinstance(item, TupleType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isTuple.append(mapping_as_str)
            isTuple = [i for i in isTuple if i != 'item']

        elif isinstance(item, DictType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isDict.append(mapping_as_str)
            isDict = [i for i in isDict if i != 'item']

        elif isinstance(item, IntType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isInt.append(mapping_as_str)
            isInt = [i for i in isInt if i != 'item']

        elif isinstance(item, FloatType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isFloat.append(mapping_as_str)
            isFloat = [i for i in isFloat if i != 'item']

        elif isinstance(item, StringType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isString.append(mapping_as_str)
            isString = [i for i in isString if i != 'item']

        else:
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    other.append(mapping_as_str)
            other = [i for i in other if i != 'item']

    except (TypeError, AttributeError), e:
        print e

print '\n isClass:', len(isClass), isClass
print '  isList:', len(isList), isList
print ' isTuple:', len(isTuple), isTuple
print '  isDict:', len(isDict), isDict
print '   isInt:', len(isInt), isInt
print ' isFloat:', len(isFloat), isFloat
print 'isString:', len(isString), isString
print '   other:', len(other), other

# my output and the output I wanted
'''
MIXED_DATA_TYPES total count: 14

 isClass: 2 ['Class_1', 'Class_2']
  isList: 2 ['list_1', 'list_2']
 isTuple: 2 ['tuple_1', 'tuple_2']
  isDict: 2 ['dict_1', 'dict_2']
   isInt: 2 ['x', 'y']
 isFloat: 2 ['pie', 'eee']
isString: 2 ['house', 'cabin']
   other: 0 []
'''

#20


1  

On python3, this function will get the outer most name in the stack:

在python3中,这个函数会得到堆栈中最外层的名字:

import inspect


def retrieve_name(var):
        """
        Gets the name of var. Does it from the out most frame inner-wards.
        :param var: variable to get name from.
        :return: string
        """
        for fi in reversed(inspect.stack()):
            names = [var_name for var_name, var_val in fi.frame.f_locals.items() if var_val is var]
            if len(names) > 0:
                return names[0]

It is useful anywhere on the code. Traverses the reversed stack looking for the first match.

它在代码的任何地方都是有用的。遍历反向堆栈以查找第一个匹配。

#21


0  

you can use easydict

您可以使用easydict

>>> from easydict import EasyDict as edict
>>> d = edict({'foo':3, 'bar':{'x':1, 'y':2}})
>>> d.foo
3
>>> d.bar.x
1
>>> d = edict(foo=3)
>>> d.foo
3

another example:

另一个例子:

>>> d = EasyDict(log=False)
>>> d.debug = True
>>> d.items()
[('debug', True), ('log', False)]

#22


0  

While this is probably an awful idea, it is along the same lines as rlotun's answer but it'll return the correct result more often.

虽然这可能是一个糟糕的想法,但它和rlotun的答案是一样的,但它会更经常地返回正确的结果。

import inspect
def getVarName(getvar):
  frame = inspect.currentframe()
  callerLocals = frame.f_back.f_locals
  for k, v in list(callerLocals.items()):
    if v is getvar():
      callerLocals.pop(k)
      try:
        getvar()
        callerLocals[k] = v
      except NameError:
        callerLocals[k] = v
        del frame
        return k
  del frame

You call it like this:

你这样称呼它:

bar = True
foo = False
bean = False
fooName = getVarName(lambda: foo)
print(fooName) # prints "foo"

#23


0  

I uploaded a solution to pypi. It's a module defining an equivalent of C#'s nameof function.

我将一个解决方案上传到pypi。它是一个定义等价于c#的nameof函数的模块。

It iterates through bytecode instructions for the frame its called in, getting the names of variables/attributes passed to it. The names are found in the .argrepr of LOAD instructions following the function's name.

它遍历它调用的框架的字节码指令,获取传递给它的变量/属性的名称。在函数名之后的LOAD指令的.argrepr中可以找到这些名称。

#24


0  

should get list then return

应该获取列表然后返回吗

def get_var_name(**kwargs):
    """get variable name
        get_var_name(var = var)
    Returns:
        [str] -- var name
    """
    return list(kwargs.keys())[0]

#25


-3  

>>> a = 1
>>> b = 1
>>> id(a)
34120408
>>> id(b)
34120408
>>> a is b
True
>>> id(a) == id(b)
True

this way get varname for a maybe 'a' or 'b'.

这样就可以得到a或者b的varname。

#1


27  

Are you trying to do this?

你想这么做吗?

dict( (name,eval(name)) for name in ['some','list','of','vars'] )

Example

例子

>>> some= 1
>>> list= 2
>>> of= 3
>>> vars= 4
>>> dict( (name,eval(name)) for name in ['some','list','of','vars'] )
{'list': 2, 'some': 1, 'vars': 4, 'of': 3}

#2


119  

As unwind said, this isn't really something you do in Python - variables are actually name mappings to objects.

正如unwind所言,这并不是在Python中做的事情——变量实际上是对象的名称映射。

However, here's one way to try and do it:

然而,有一种方法可以尝试:

 >>> a = 1
 >>> for k, v in list(locals().iteritems()):
         if v is a:
             a_as_str = k
 >>> a_as_str
 a
 >>> type(a_as_str)
 'str'

#3


52  

I've wanted to do this quite a lot. This hack is very similar to rlotun's suggestion, but it's a one-liner, which is important to me:

我想做很多事情。这次黑客攻击与rlotun的建议非常相似,但它是一种简单的东西,对我来说很重要:

blah = 1
blah_name = [ k for k,v in locals().iteritems() if v is blah][0]

#4


15  

This is not possible in Python, which really doesn't have "variables". Python has names, and there can be more than one name for the same object.

这在Python中是不可能的,因为它实际上没有“变量”。Python有名称,同一对象可以有多个名称。

#5


14  

This is a hack. It will not work on all Python implementations distributions (in particular, those that do not have traceback.extract_stack.)

这是一个黑客。它不能在所有的Python实现发行版上工作(特别是那些没有traceback.extract_stack的发行版)。

import traceback

def make_dict(*expr):
    (filename,line_number,function_name,text)=traceback.extract_stack()[-2]
    begin=text.find('make_dict(')+len('make_dict(')
    end=text.find(')',begin)
    text=[name.strip() for name in text[begin:end].split(',')]
    return dict(zip(text,expr))

bar=True
foo=False
print(make_dict(bar,foo))
# {'foo': False, 'bar': True}

Note that this hack is fragile:

注意,这种方法是脆弱的:

make_dict(bar,
          foo)

(calling make_dict on 2 lines) will not work.

(用两条线调用make_dict)将不起作用。

Instead of trying to generate the dict out of the values foo and bar, it would be much more Pythonic to generate the dict out of the string variable names 'foo' and 'bar':

与其试图从foo和bar的值生成dict类型,不如从字符串变量name 'foo'和'bar'中生成dict类型:

dict([(name,locals()[name]) for name in ('foo','bar')])

#6


10  

I think my problem will help illustrate why this question is useful, and it may give a bit more insight into how to answer it. I wrote a small function to do a quick inline head check on various variables in my code. Basically, it lists the variable name, data type, size, and other attributes, so I can quickly catch any mistakes I've made. The code is simple:

我认为我的问题将有助于说明为什么这个问题是有用的,它可能会提供更多关于如何回答它的见解。我编写了一个小函数来对代码中的各种变量进行快速内联检查。基本上,它列出了变量名、数据类型、大小和其他属性,因此我可以快速地捕捉到我所犯的错误。代码很简单:

def details(val):
  vn = val.__name__                 #  If such a thing existed
  vs = str(val)
  print("The Value of "+ str(vn) + " is " + vs)
  print("The data type of " + vn + " is " + str(type(val)))

So if you have some complicated dictionary / list / tuple situation, it would be quite helpful to have the interpreter return the variable name you assigned. For instance, here is a weird dictionary:

因此,如果您有一些复杂的字典/列表/元组情况,让解释器返回您分配的变量名将非常有用。例如,这里有一本奇怪的字典:

m = 'abracadabra'
mm=[]    
for n in m:
  mm.append(n)
mydic = {'first':(0,1,2,3,4,5,6),'second':mm,'third':np.arange(0.,10)}



details(mydic)

The Value of mydic is {'second': ['a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a'], 'third': array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.]), 'first': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
The data type of mydic is <type 'dict'>

details(mydic['first'])
The Value of mydic['first'] is (0, 1, 2, 3, 4, 5, 6)]
The data type of mydic['first'] is <type 'list'>

details(mydic.keys())
The Value of mydic.keys() is ['second', 'third', 'first']
The data type of mydic.keys() is <type 'tuple'>

details(mydic['second'][0])
The Value of mydic['second'][0] is a
The data type of mydic['second'][0] is <type 'str'>

I'm not sure if I put this in the right place, but I thought it might help. I hope it does.

我不确定我是否把它放在正确的地方,但我认为它可能会有所帮助。我希望它能。

#7


8  

Just for reference, here is answer using keywords:

仅供参考,以下是使用关键词的回答:

Collect the arguments using the ** specifier in the function’s parameter list; this gives you the keyword arguments as a dictionary.

使用函数参数列表中的**说明符收集参数;这将为您提供关键字参数作为字典。

source

Solution:

>>> def get_var_name(**kwargs): return kwargs.keys()[0]

used like :

使用:

>>> var  = 'this is variable'
>>> get_var_name(var=var)
'var'

original answer: https://*.com/a/19201952/2628312

最初的回答:https://*.com/a/19201952/2628312

#8


7  

I wrote a neat little useful function based on the answer to this question. I'm putting it here in case it's useful.

我根据这个问题的答案写了一个很有用的函数。我把它放在这里以防它有用。

def what(obj, callingLocals=locals()):
    """
    quick function to print name of input and value. 
    If not for the default-Valued callingLocals, the function would always
    get the name as "obj", which is not what I want.    
    """
    for k, v in list(callingLocals.items()):
         if v is obj:
            name = k
    print(name, "=", obj)

usage:

用法:

>> a = 4
>> what(a)
a = 4
>>|

#9


6  

In python 3 this is easy

在python 3中,这很简单

myVariable = 5
for v in locals():
  if id(v) == id("myVariable"):
    print(v, locals()[v])

this will print:

这将打印:

myVariable 5

myVariable 5

#10


5  

I find that if you already have a specific list of values, that the way described by @S. Lotts is the best; however, the way described below works well to get all variables and Classes added throughout the code WITHOUT the need to provide variable name though you can specify them if you want. Code can be extend to exclude Classes.

我发现,如果您已经有了一个特定的值列表,就像@S描述的那样。洛特是最好的;但是,下面描述的方法可以很好地在整个代码中添加所有变量和类,而不需要提供变量名,但是如果需要的话可以指定它们。可以扩展代码以排除类。

import types
import math  # mainly showing that you could import what you will before d

# Everything after this counts
d = dict(globals())

def kv_test(k,v):
    return (k not in d and 
            k not in ['d','args'] and
            type(v) is not types.FunctionType)

def magic_print(*args):
    if len(args) == 0: 
        return {k:v for k,v in globals().iteritems() if kv_test(k,v)}
    else:
        return {k:v for k,v in magic_print().iteritems() if k in args}

if __name__ == '__main__':
    foo = 1
    bar = 2
    baz = 3
    print magic_print()
    print magic_print('foo')
    print magic_print('foo','bar')

Output:

输出:

{'baz': 3, 'foo': 1, 'bar': 2}
{'foo': 1}
{'foo': 1, 'bar': 2}

#11


4  

In reading the thread, I saw an awful lot of friction. It's easy enough to give a bad answer, then let someone give the correct answer. Anyway, here is what I found.

在阅读这条线时,我看到了大量的摩擦。给出一个错误的答案很容易,然后让别人给出正确的答案。总之,这是我发现的。

From: [effbot.org] (http://effbot.org/zone/python-objects.htm#names)

来自:[effbot.org](http://effbot.org/zone/python-objects.htm名称)

The names are a bit different — they’re not really properties of the object, and the object itself doesn't know what it’s called.

名字有点不同——它们不是对象的真正属性,对象本身不知道它叫什么。

An object can have any number of names, or no name at all.

对象可以有任意数量的名称,或者根本没有名称。

Names live in namespaces (such as a module namespace, an instance namespace, a function’s local namespace).

名称存在于名称空间中(例如模块名称空间、实例名称空间、函数的本地名称空间)。

Note: that it says the object itself doesn’t know what it’s called, so that was the clue. Python objects are not self-referential. Then it says, Names live in namespaces. We have this in TCL/TK. So maybe my answer will help (but it did help me)

注意:它说对象本身不知道它叫什么,所以这就是线索。Python对象不是自引用的。然后它说,名称在名称空间中存在。我们在TCL/TK中有这个。也许我的答案会有帮助(但它确实帮助了我)


    jj = 123
    print eval("'" + str(id(jj)) + "'")
    print dir()

166707048
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'jj']

So there is 'jj' at the end of the list.

所以,“jj”在名单的最后。

Rewrite the code as:

重写代码为:


    jj = 123
    print eval("'" + str(id(jj)) + "'")
    for x in dir():
        print id(eval(x))

161922920
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'jj']
3077447796
136515736
3077408320
3077656800
136515736
161922920

This nasty bit of code id's the name of variable/object/whatever-you-pedantics-call-it.

这个讨厌的代码id的名称是变量/对象/无论你怎么称呼它。

So, there it is. The memory address of 'jj' is the same when we look for it directly, as when we do the dictionary look up in global name space. I'm sure you can make a function to do this. Just remember which namespace your variable/object/wypci is in.

所以,就是这样。当我们直接查找jj时,它的内存地址是相同的,就像我们在全局名称空间中查找字典一样。我相信你可以用一个函数来做这个。只需记住变量/对象/wypci所在的名称空间。

QED.

QED。

#12


4  

Python3. Use inspect to capture the calling local namespace then use ideas presented here. Can return more than one answer as has been pointed out.

Python3。使用inspect来捕获调用的本地名称空间,然后使用这里提供的想法。可以返回已指出的多个答案。

def varname(var):
  import inspect
  frame = inspect.currentframe()
  var_id = id(var)
  for name in frame.f_back.f_locals.keys():
    try:
      if id(eval(name)) == var_id:
        return(name)
    except:
      pass

#13


3  

Here's the function I created to read the variable names. It's more general and can be used in different applications:

这是我创建用来读取变量名的函数。它更通用,可用于不同的应用:

def get_variable_name(*variable):
    '''gets string of variable name
    inputs
        variable (str)
    returns
        string
    '''
    if len(variable) != 1:
        raise Exception('len of variables inputed must be 1')
    try:
        return [k for k, v in locals().items() if v is variable[0]][0]
    except:
        return [k for k, v in globals().items() if v is variable[0]][0]

To use it in the specified question:

在指定的问题中使用:

>>> foo = False
>>> bar = True
>>> my_dict = {get_variable_name(foo):foo, 
               get_variable_name(bar):bar}
>>> my_dict
{'bar': True, 'foo': False}

#14


2  

import re
import traceback

pattren = re.compile(r'[\W+\w+]*get_variable_name\((\w+)\)')
def get_variable_name(x):
    return pattren.match( traceback.extract_stack(limit=2)[0][3]) .group(1)

a = 1
b = a
c = b
print get_variable_name(a)
print get_variable_name(b)
print get_variable_name(c)

#15


1  

Most objects don't have a __name__ attribute. (Classes, functions, and modules do; any more builtin types that have one?)

大多数对象都没有__name__属性。(类、函数和模块有;还有其他有内置类型的吗?)

What else would you expect for print(my_var.__name__) other than print("my_var")? Can you simply use the string directly?

除了print(my_var.__name__)之外,您还希望打印什么?你能直接使用字符串吗?

You could "slice" a dict:

你可以“切片”一条法令:

def dict_slice(D, keys, default=None):
  return dict((k, D.get(k, default)) for k in keys)

print dict_slice(locals(), ["foo", "bar"])
# or use set literal syntax if you have a recent enough version:
print dict_slice(locals(), {"foo", "bar"})

Alternatively:

另外:

throw = object()  # sentinel
def dict_slice(D, keys, default=throw):
  def get(k):
    v = D.get(k, throw)
    if v is not throw:
      return v
    if default is throw:
      raise KeyError(k)
    return default
  return dict((k, get(k)) for k in keys)

#16


1  

Well, I encountered the very same need a few days ago and had to get a variable's name which was pointing to the object itself.

几天前,我遇到了同样的问题,我需要得到一个指向对象本身的变量名。

And why was it so necessary?

为什么这么必要呢?

In short I was building a plug-in for Maya. The core plug-in was built using C++ but the GUI is drawn through Python(as its not processor intensive). Since I, as yet, don't know how to return multiple values from the plug-in except the default MStatus, therefore to update a dictionary in Python I had to pass the the name of the variable, pointing to the object implementing the GUI and which contained the dictionary itself, to the plug-in and then use the MGlobal::executePythonCommand() to update the dictionary from the global scope of Maya.

简而言之,我正在为Maya构建一个插件。核心插件是使用c++构建的,但是GUI是通过Python绘制的(因为它不是处理器密集型的)。然而,因为我不知道如何从插件除了返回多个值默认MStatus,因此更新字典在Python中我不得不通过变量的名称,指向对象实现GUI和它包含字典本身,插件,然后使用MGlobal::executePythonCommand()来更新字典从全球玛雅的范围。

To do that what I did was something like:

我所做的是:

import time

class foo(bar):

    def __init__(self):
        super(foo, self).__init__()
        self.time = time.time() #almost guaranteed to be unique on a single computer

    def name(self):
        g = globals()
        for x in g:
            if isinstance(g[x], type(self)):
                if g[x].time == self.time:
                    return x
                    #or you could:
                    #return filter(None,[x if g[x].time == self.time else None for x in g if isinstance(g[x], type(self))])
                    #and return all keys pointing to object itself

I know that it is not the perfect solution in in the globals many keys could be pointing to the same object e.g.:

我知道这不是一个完美的解决方案,在全局中,许多键可以指向同一个对象,例如:

a = foo()
b = a
b.name()
>>>b
or
>>>a

and that the approach isn't thread-safe. Correct me if I am wrong.

而且这种方法不是线程安全的。如果我错了请纠正我。

At least this approach solved my problem by getting the name of any variable in the global scope which pointed to the object itself and pass it over to the plug-in, as argument, for it use internally.

至少,这种方法通过获取全局范围中指向对象本身的任何变量的名称并将其作为参数传递给插件来解决我的问题。

I tried this on int (the primitive integer class) but the problem is that these primitive classes don't get bypassed (please correct the technical terminology used if its wrong). You could re-implement int and then do int = foo but a = 3 will never be an object of foo but of the primitive. To overcome that you have to a = foo(3) to get a.name() to work.

我在int(原始整数类)上尝试过这种方法,但问题是这些原始类不会被绕过(如果错误,请纠正所使用的技术术语)。你可以重新实现int然后做int = foo但a = 3永远不会是foo的对象,而是原语的对象。要克服这个问题,必须使用a = foo(3)才能使a.name()工作。

#17


1  

With python 2.7 and newer there is also dictionary comprehension which makes it a bit shorter. If possible I would use getattr instead eval (eval is evil) like in the top answer. Self can be any object which has the context your a looking at. It can be an object or locals=locals() etc.

在python 2.7和更新版本中,还有字典理解功能,这使它更短一些。如果可能的话,我将使用getattr代替eval (eval是邪恶的),就像上面的答案一样。Self可以是任何有上下文的对象。它可以是对象或局部=局部变量()等。

{name: getattr(self, name) for name in ['some', 'vars', 'here]}

#18


1  

Maybe I'm overthinking this but..

也许我想得太多了…

str_l = next((k for k,v in locals().items() if id(l) == id(v)))


>>> bar = True
>>> foo = False
>>> my_dict=dict(bar=bar, foo=foo)
>>> next((k for k,v in locals().items() if id(bar) == id(v)))
'bar'
>>> next((k for k,v in locals().items() if id(foo) == id(v)))
'foo'
>>> next((k for k,v in locals().items() if id(my_dict) == id(v)))
'my_dict'

#19


1  

I was working on a similar problem. @S.Lott said "If you have the list of variables, what's the point of "discovering" their names?" And my answer is just to see if it could be done and if for some reason you want to sort your variables by type into lists. So anyways, in my research I came came across this thread and my solution is a bit expanded and is based on @rlotun solution. One other thing, @unutbu said, "This idea has merit, but note that if two variable names reference the same value (e.g. True), then an unintended variable name might be returned." In this exercise that was true so I dealt with it by using a list comprehension similar to this for each possibility: isClass = [i for i in isClass if i != 'item']. Without it "item" would show up in each list.

我正在研究一个类似的问题。@。洛特说:“如果你有变量列表,那么“发现”它们的名字有什么意义呢?”我的答案是看看是否可以做到如果出于某种原因你想把变量按类型排序成列表。无论如何,在我的研究中,我遇到了这个线程,我的解决方案是扩展的,基于@rlotun解决方案。另一件事,@unutbu说,“这个想法是有价值的,但是请注意,如果两个变量名引用相同的值(例如,True),那么可能会返回一个意外的变量名。”在这个练习中,这是对的,所以我使用了一个类似于对每一种可能性的列表理解:isClass = [I for I In isClass if I != 'item']。没有它,“项目”就会出现在每个列表中。

__metaclass__ = type

from types import *

class Class_1: pass
class Class_2: pass
list_1 = [1, 2, 3]
list_2 = ['dog', 'cat', 'bird']
tuple_1 = ('one', 'two', 'three')
tuple_2 = (1000, 2000, 3000)
dict_1 = {'one': 1, 'two': 2, 'three': 3}
dict_2 = {'dog': 'collie', 'cat': 'calico', 'bird': 'robin'}
x = 23
y = 29
pie = 3.14159
eee = 2.71828
house = 'single story'
cabin = 'cozy'

isClass = []; isList = []; isTuple = []; isDict = []; isInt = []; isFloat = []; isString = []; other = []

mixedDataTypes = [Class_1, list_1, tuple_1, dict_1, x, pie, house, Class_2, list_2, tuple_2, dict_2, y, eee, cabin]

print '\nMIXED_DATA_TYPES total count:', len(mixedDataTypes)

for item in mixedDataTypes:
    try:
        # if isinstance(item, ClassType): # use this for old class types (before 3.0)
        if isinstance(item, type):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isClass.append(mapping_as_str)
            isClass = [i for i in isClass if i != 'item']

        elif isinstance(item, ListType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isList.append(mapping_as_str)
            isList = [i for i in isList if i != 'item']

        elif isinstance(item, TupleType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isTuple.append(mapping_as_str)
            isTuple = [i for i in isTuple if i != 'item']

        elif isinstance(item, DictType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isDict.append(mapping_as_str)
            isDict = [i for i in isDict if i != 'item']

        elif isinstance(item, IntType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isInt.append(mapping_as_str)
            isInt = [i for i in isInt if i != 'item']

        elif isinstance(item, FloatType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isFloat.append(mapping_as_str)
            isFloat = [i for i in isFloat if i != 'item']

        elif isinstance(item, StringType):
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    isString.append(mapping_as_str)
            isString = [i for i in isString if i != 'item']

        else:
            for k, v in list(locals().iteritems()):
                if v is item:
                    mapping_as_str = k
                    other.append(mapping_as_str)
            other = [i for i in other if i != 'item']

    except (TypeError, AttributeError), e:
        print e

print '\n isClass:', len(isClass), isClass
print '  isList:', len(isList), isList
print ' isTuple:', len(isTuple), isTuple
print '  isDict:', len(isDict), isDict
print '   isInt:', len(isInt), isInt
print ' isFloat:', len(isFloat), isFloat
print 'isString:', len(isString), isString
print '   other:', len(other), other

# my output and the output I wanted
'''
MIXED_DATA_TYPES total count: 14

 isClass: 2 ['Class_1', 'Class_2']
  isList: 2 ['list_1', 'list_2']
 isTuple: 2 ['tuple_1', 'tuple_2']
  isDict: 2 ['dict_1', 'dict_2']
   isInt: 2 ['x', 'y']
 isFloat: 2 ['pie', 'eee']
isString: 2 ['house', 'cabin']
   other: 0 []
'''

#20


1  

On python3, this function will get the outer most name in the stack:

在python3中,这个函数会得到堆栈中最外层的名字:

import inspect


def retrieve_name(var):
        """
        Gets the name of var. Does it from the out most frame inner-wards.
        :param var: variable to get name from.
        :return: string
        """
        for fi in reversed(inspect.stack()):
            names = [var_name for var_name, var_val in fi.frame.f_locals.items() if var_val is var]
            if len(names) > 0:
                return names[0]

It is useful anywhere on the code. Traverses the reversed stack looking for the first match.

它在代码的任何地方都是有用的。遍历反向堆栈以查找第一个匹配。

#21


0  

you can use easydict

您可以使用easydict

>>> from easydict import EasyDict as edict
>>> d = edict({'foo':3, 'bar':{'x':1, 'y':2}})
>>> d.foo
3
>>> d.bar.x
1
>>> d = edict(foo=3)
>>> d.foo
3

another example:

另一个例子:

>>> d = EasyDict(log=False)
>>> d.debug = True
>>> d.items()
[('debug', True), ('log', False)]

#22


0  

While this is probably an awful idea, it is along the same lines as rlotun's answer but it'll return the correct result more often.

虽然这可能是一个糟糕的想法,但它和rlotun的答案是一样的,但它会更经常地返回正确的结果。

import inspect
def getVarName(getvar):
  frame = inspect.currentframe()
  callerLocals = frame.f_back.f_locals
  for k, v in list(callerLocals.items()):
    if v is getvar():
      callerLocals.pop(k)
      try:
        getvar()
        callerLocals[k] = v
      except NameError:
        callerLocals[k] = v
        del frame
        return k
  del frame

You call it like this:

你这样称呼它:

bar = True
foo = False
bean = False
fooName = getVarName(lambda: foo)
print(fooName) # prints "foo"

#23


0  

I uploaded a solution to pypi. It's a module defining an equivalent of C#'s nameof function.

我将一个解决方案上传到pypi。它是一个定义等价于c#的nameof函数的模块。

It iterates through bytecode instructions for the frame its called in, getting the names of variables/attributes passed to it. The names are found in the .argrepr of LOAD instructions following the function's name.

它遍历它调用的框架的字节码指令,获取传递给它的变量/属性的名称。在函数名之后的LOAD指令的.argrepr中可以找到这些名称。

#24


0  

should get list then return

应该获取列表然后返回吗

def get_var_name(**kwargs):
    """get variable name
        get_var_name(var = var)
    Returns:
        [str] -- var name
    """
    return list(kwargs.keys())[0]

#25


-3  

>>> a = 1
>>> b = 1
>>> id(a)
34120408
>>> id(b)
34120408
>>> a is b
True
>>> id(a) == id(b)
True

this way get varname for a maybe 'a' or 'b'.

这样就可以得到a或者b的varname。