我已经读了如何获得一个函数名作为字符串?。

如何对变量做同样的事情呢?与函数相反,Python变量没有__name__属性。

换句话说,如果我有一个变量,比如:

foo = dict()
foo['bar'] = 2

我正在寻找一个函数/属性,例如retrieve_name(),以便从这个列表中创建一个DataFrame in Pandas,其中列名由实际字典的名称给出:

# List of dictionaries for my DataFrame
list_of_dicts = [n_jobs, users, queues, priorities]
columns = [retrieve_name(d) for d in list_of_dicts] 

当前回答

这里有一种方法。我不建议在任何重要的事情上使用它,因为它会很脆。但这是可以做到的。

创建一个使用inspect模块查找调用它的源代码的函数。然后可以解析源代码,以识别想要检索的变量名。例如,这里有一个名为autodict的函数,它接受一个变量列表,并返回一个将变量名映射到变量值的字典。例如:

x = 'foo'
y = 'bar'
d = autodict(x, y)
print d

将:

{'x': 'foo', 'y': 'bar'}

检查源代码本身比搜索locals()或globals()更好,因为后一种方法不会告诉您哪些变量是您想要的。

无论如何,代码如下:

def autodict(*args):
    get_rid_of = ['autodict(', ',', ')', '\n']
    calling_code = inspect.getouterframes(inspect.currentframe())[1][4][0]
    calling_code = calling_code[calling_code.index('autodict'):]
    for garbage in get_rid_of:
        calling_code = calling_code.replace(garbage, '')
    var_names, var_values = calling_code.split(), args
    dyn_dict = {var_name: var_value for var_name, var_value in
                zip(var_names, var_values)}
    return dyn_dict

该动作发生在inspect的行中。Getouterframes,它返回调用autodict的代码中的字符串。

这种魔法的明显缺点是,它对源代码的结构做出了假设。当然,如果它在解释器内部运行,它根本就不起作用。

其他回答

>> my_var = 5
>> my_var_name = [ k for k,v in locals().items() if v == my_var][0]
>> my_var_name 
'my_var'

如果myvar指向另一个变量,如果你得到一个错误,试试这个(由@mherzog建议)-

 >> my_var = 5
>> my_var_name = [ k for k,v in locals().items() if v is my_var][0]
>> my_var_name 
'my_var'

locals() -返回包含当前作用域局部变量的字典。 通过遍历这个字典,我们可以检查值等于定义变量的键,只需提取键就可以得到字符串格式的变量文本。

From(稍作改动后) https://www.tutorialspoint.com/How-to-get-a-variable-name-as-a-string-in-Python

也许这很有用:

def Retriever(bar):
    return (list(globals().keys()))[list(map(lambda x: id(x), list(globals().values()))).index(id(bar))]

该函数遍历全局作用域的值的ID列表(可以编辑命名空间),根据其ID找到想要/需要的var或函数的索引,然后根据获得的索引从全局名称列表中返回名称。

在Python中,def和class关键字将特定的名称绑定到它们定义的对象(函数或类)。类似地,模块通过在文件系统中调用某个特定的名称来命名。在这三种情况下,都有一种明显的方法可以将“规范”名称分配给有问题的对象。

然而,对于其他类型的对象,这样的规范名称可能根本不存在。例如,考虑列表中的元素。列表中的元素不是单独命名的,在程序中引用它们的唯一方法完全可能是在包含它们的列表上使用列表索引。如果将这样一个对象列表传递到函数中,则不可能为值分配有意义的标识符。

Python不会将赋值对象左边的名称保存到赋值对象中,因为:

这需要在多个冲突的对象中找出哪个名称是“规范的”, 对于那些从未赋值给显式变量名的对象来说,这是没有意义的, 这样效率会非常低, 实际上没有其他现存的语言能做到这一点。

例如,使用lambda定义的函数将始终具有"name" <lambda>,而不是特定的函数名。

最好的方法是简单地要求调用者传入一个(可选的)名称列表。如果输入“…”,“…”'太麻烦了,你可以接受一个包含逗号分隔的名字列表的字符串(像namedtuple那样)。

这是另一种基于输入变量内容的方法:

(它返回第一个与输入变量匹配的变量名,否则为None。可以修改它,以获得所有与输入变量具有相同内容的变量名)

def retrieve_name(x, Vars=vars()):
    for k in Vars:
        if isinstance(x, type(Vars[k])):
            if x is Vars[k]:
                return k
    return None

下面的方法将不会返回变量的名称,但如果变量在全局作用域可用,则使用此方法可以轻松创建数据帧。

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}

A = [0, 1]
B = [1, 2]
pd.DataFrame(G.A + G.B) # It will return a data frame with A and B columns