我希望能够以字符串的形式获取变量的名称,但我不知道Python是否有那么多的自省功能。喜欢的东西:

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

我想这样做是因为我有一堆变量,我想把它们转换成一个字典,比如:

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

但我想要更自动的。

Python有locals()和vars(),所以我猜有一种方法。


当前回答

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

除了print("my_var"),你还期望print(my_var.__name__)有什么?你能直接使用字符串吗?

你可以"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"})

另外:

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)

其他回答

也许我想多了,但是…

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'

使用python-varname你可以很容易地做到这一点:

PIP安装python-varname

from varname import Wrapper

foo = Wrapper(True)
bar = Wrapper(False)

your_dict = {val.name: val.value for val in (foo, bar)}

print(your_dict)

# {'foo': True, 'bar': False}

声明:我是python-varname库的作者。

好吧,几天前我遇到了同样的需求,必须获得一个指向对象本身的变量名。

为什么这么有必要呢?

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.

为了做到这一点,我所做的是:

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

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

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

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

至少这种方法解决了我的问题,它在全局作用域中获取指向对象本身的任何变量的名称,并将其作为参数传递给插件,供它在内部使用。

我在int(原始整数类)上尝试了这一点,但问题是这些原始类不会被绕过(请纠正使用的技术术语,如果它是错误的)。你可以重新实现int,然后执行int = foo,但a = 3永远不会是foo的对象,而是原语的对象。为了克服这个问题,你必须使用a = foo(3)来让a.name()工作。

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

通过这种方式,可以获得'a'或'b'的varname。

它不会返回变量的名称,但您可以轻松地从全局变量创建字典。

class CustomDict(dict):
    def __add__(self, other):
        return CustomDict({**self, **other})

class GlobalBase(type):
    def __getattr__(cls, key):
        return CustomDict({key: globals()[key]})

    def __getitem__(cls, keys):
        return CustomDict({key: globals()[key] for key in keys})

class G(metaclass=GlobalBase):
    pass

x, y, z = 0, 1, 2

print('method 1:', G['x', 'y', 'z']) # Outcome: method 1: {'x': 0, 'y': 1, 'z': 2}
print('method 2:', G.x + G.y + G.z) # Outcome: method 2: {'x': 0, 'y': 1, 'z': 2}