将变量的名称作为字符串

时间:2013-08-25 02:58:26

标签: python python-2.x

该主题讨论如何在Python中将函数名称作为字符串获取: How to get a function name as a string in Python?

如何为变量做同样的事情? (请注意,Python变量没有属性__name__,至少在Python 2.7.x中)

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

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

我正在寻找一个功能/属性,例如retrieve_name

retrieve_name(foo) 

返回字符串'foo'

更新

由于人们在问我为什么要这样做,这里有一个例子。我想create a DataFrame in Pandas from this list列名由实际词典的名称给出:

# List of dictionaries for my DataFrame
list_of_dicts = [n_jobs, users, queues, priorities]

26 个答案:

答案 0 :(得分:73)

Python中唯一具有规范名称的对象是模块,函数和类,当然,在定义函数或类或导入模块之后,无法保证此规范名称在任何命名空间中都有任何意义。创建对象后也可以修改这些名称,因此它们可能并不总是特别值得信赖。

你不想做什么without recursively walking the tree of named objects;名称是对象的单向引用。常见或花园种类的Python对象不包含对其名称的引用。想象一下,如果每个整数,每个字典,每个列表,每个布尔值都需要维护表示引用它的名称的字符串列表!这将是一个实施的噩梦,对程序员来说几乎没有任何好处。

答案 1 :(得分:58)

即使变量值没有指向名称,您也可以访问每个已分配变量及其值的列表,所以我很惊讶只有一个人建议在那里循环查找您的var名称。

有人在回答中提到你可能需要走堆栈并检查每个人的本地人和全局变量以查找foo,但是如果在您调用此foo的范围内分配retrieve_name 1}}函数,您可以使用inspect的{​​{1}}来获取所有这些局部变量。

我的解释可能有点过于冗长(也许我应该使用“foo”更少的单词),但这是它在代码中的外观(请注意,如果分配了多个变量相同的值,您将获得这两个变量名称):

current frame

如果您从另一个函数调用此函数,请执行以下操作:

import inspect

x,y,z = 1,2,3

def retrieve_name(var):
    callers_local_vars = inspect.currentframe().f_back.f_locals.items()
    return [var_name for var_name, var_val in callers_local_vars if var_val is var]

print retrieve_name(y)

您希望def foo(bar): return retrieve_name(bar) foo(baz) 代替baz,您只需要进一步返回范围即可。这可以通过在bar初始化中添加额外的.f_back来完成。

请在此处查看示例:ideone

答案 2 :(得分:20)

我不相信这是可能的。请考虑以下示例:

>>> a = []
>>> b = a
>>> id(a)
140031712435664
>>> id(b)
140031712435664

ab指向同一个对象,但对象无法知道哪些变量指向它。

答案 3 :(得分:17)

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

它在代码的任何地方都很有用。遍历反向堆栈寻找第一场比赛。

答案 4 :(得分:12)

def name(**variables):
    return [x for x in variables]

它的使用方式如下:

name(variable=variable)

答案 5 :(得分:7)

这是一种方法。我不会推荐任何重要的东西,因为它会非常脆弱。但它可以做到。

创建一个使用autodict模块查找调用它的源代码的函数。然后,您可以解析源代码以标识要检索的变量名称。例如,这里有一个名为x = 'foo' y = 'bar' d = autodict(x, y) print d 的函数,它接受一个变量列表并返回一个字典映射变量名称到它们的值。 E.g:

{'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的行中,该行返回名为var dm = new double[size][]; for (var i = 0; i < size; i++) { dm[i] = new double[size]; for (var j = 0; j < i+1; j++) { dm[i][j] = distance(data[i], data[j]); dm[j][i] = dm[i][j]; } } private double GetValueOfDM(int row, int column, double[][] dm) { return dm[row][column]; } 的代码中的字符串。

这种神奇的明显缺点是它假设了源代码的结构。当然,如果它在翻译中运行,它根本不会起作用。

答案 6 :(得分:6)

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

locals()-返回包含当前作用域的局部变量的字典。 通过遍历该字典,我们可以检查具有等于定义的变量的值的键,仅提取键将为我们提供字符串格式的变量文本。

来自(稍作更改) https://www.tutorialspoint.com/How-to-get-a-variable-name-as-a-string-in-Python

答案 7 :(得分:5)

使用Python 3.8可以简单地使用f字符串调试功能:

>>> foo = dict()
>>> f'{foo=}'.split('=')[0]
'foo' 

答案 8 :(得分:5)

我编写了程序包sorcery来稳健地进行这种魔术。您可以编写:

from sorcery import dict_of

columns = dict_of(n_jobs, users, queues, priorities)

并将其传递给数据框构造函数。等效于:

columns = dict(n_jobs=n_jobs, users=users, queues=queues, priorities=priorities)

答案 9 :(得分:4)

>>> locals()['foo']
{}
>>> globals()['foo']
{}

如果你想编写自己的函数,可以这样做,你可以检查locals中定义的变量,然后检查全局变量。如果找不到任何内容,您可以在id()上进行比较,以查看变量是否指向内存中的相同位置。

如果您的变量在类中,则可以使用className。 dict .keys()或vars(self)来查看您的变量是否已定义。

答案 10 :(得分:3)

我认为在Python中执行此操作非常困难,因为您永远不会知道您正在使用的变量的名称。所以,在他的例子中,你可以这样做:

而不是:

list_of_dicts = [n_jobs, users, queues, priorities]

dict_of_dicts = {"n_jobs" : n_jobs, "users" : users, "queues" : queues, "priorities" : priorities}

答案 11 :(得分:3)

我有一种方法,虽然不是最有效的 ...但是有效! (它不包含任何高级模块)。

基本上,它将变量的ID globals()变量的ID 进行比较,然后返回匹配的名称。

def getVariableName(variable, globalVariables=globals().copy()):
    """ Get Variable Name as String by comparing its ID to globals() Variables' IDs

        args:
            variable(var): Variable to find name for (Obviously this variable has to exist)

        kwargs:
            globalVariables(dict): Copy of the globals() dict (Adding to Kwargs allows this function to work properly when imported from another .py)
    """
    for globalVariable in globalVariables:
        if id(variable) == id(globalVariables[globalVariable]): # If our Variable's ID matches this Global Variable's ID...
            return globalVariable # Return its name from the Globals() dict

答案 12 :(得分:3)

许多答案仅返回一个变量名。但是,如果多个变量具有相同的值,那将无法正常工作。这是Amr Sharaki答案的一种变体,如果更多的变量具有相同的值,则返回多个结果。

services.AddCors(o => o.AddPolicy("CorsPolicy", builder =>{
                builder
                .AllowAnyMethod()
                .AllowAnyHeader()
                .WithOrigins("http://localhost:4200","other domains");
                
            }));

答案 13 :(得分:3)

在Python中,defclass关键字将特定名称绑定到它们定义的对象(函数或类)。类似地,模块由于在文件系统中被称为特定的东西而被赋予名称。在所有这三种情况下,都有一种明显的方法可以为相关对象分配“规范”名称。

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

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

  1. 需要弄清楚多个冲突对象中哪个名称是“规范”,
  2. 对于从未分配给显式变量名的对象
  3. ,没有任何意义
  4. 效率极低,
  5. 从字面上看,没有其他语言存在。
  6. 因此,例如,使用lambda定义的函数将始终具有“名称”<lambda>,而不是特定的函数名称。

    最好的方法是简单地要求调用者传入一个(可选的)名称列表。如果输入'...','...'太麻烦,您可以接受,例如包含以逗号分隔的名称列表的单个字符串(如namedtuple确实)。

答案 14 :(得分:2)

每当我必须这样做时,主要是在与前端通信 json 模式和常量时,我​​定义一个类如下

class Param:
    def __init__(self, name, value):
        self.name = name
        self.value = value

然后用名称和值定义变量。

frame_folder_count = Param({'name':'frame_folder_count', 'value':10})

现在您可以使用对象访问名称和值。

>>> frame_folder_count.name
'frame_folder_count'

答案 15 :(得分:2)

此函数将打印变量名称及其值:

def print_this(var):
    callers_local_vars = inspect.currentframe().f_back.f_locals.items()
    print(str([k for k, v in callers_local_vars if v is var][0])+': '+str(var))
***Input & Function call:***
my_var = 10

print_this(my_var)

***Output**:*
my_var: 10

答案 16 :(得分:1)

>>> def varname(v, scope=None): d = globals() if not scope else vars(scope); return [k for k in d if d[k] == v]
...
>>> d1 = {'a': 'ape'}; d2 = {'b': 'bear'}; d3 = {'c': 'cat'}
>>> ld = [d1, d2, d3]
>>> [varname(d) for d in ld]
[['d1'], ['d2'], ['d3']]
>>> d5 = d3
>>> [varname(d) for d in ld]
[['d1'], ['d2'], ['d3', 'd5']]
>>> def varname(v, scope=None): d = globals() if not scope else vars(scope); return [k for k in d if d[k] is v]
...
>>> [varname(d) for d in ld]
[['d1'], ['d2'], ['d3', 'd5']]

如您所见,noted here 可以有多个具有相同值甚至地址的变量,因此最好使用 using a wrapper 保留名称和数据。

答案 17 :(得分:1)

以下方法不会返回变量的名称,但是如果变量在全局范围内可用,则使用此方法可以轻松创建数据框。

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

答案 18 :(得分:1)

python-varname

Pypi Github PythonVers Travis building Codacy Codacy coverage

获取函数或类调用的变量名

安装

pip install python-varname

用法

在函数内部检索变量名

from varname import varname
def function():
    return varname()

func = function()
# func == 'func'

# available calls to retrieve
func = function(
    # ...
)

func = \
    function()

# calls lead to failure of retrieving
func = function \
    ()
func = [function()]

带有长参数列表的函数

def function(*args):
    return varname()

func = function(
    1, # I
    2, # have
    3, # a
    4, # long
    5, # argument
    6, # list
)

# func == 'var_0'

def function(*args):
    return varname(context = 20)

func = function(
    1, # I
    2, # have
    3, # a
    4, # long
    5, # argument
    6, # list
)

# func == 'func'

varname通话被深深埋葬了

def function():
    # I know that at which stack this will be called
    return varname(caller = 3)

def function1():
    return function()

def function2():
    return function1()

func = function2()
# func == 'func'

获取类对象的实例名称

class Klass:
    def __init__(self):
        self.id = varname()
    def copy(self):
        return varname()

k = Klass()
# k.id == 'k'

k2 = k.copy()
# k2 == 'k2'

varname呼叫被深深埋藏在课程中

class Klass:
    def __init__(self):
        self.id = self.some_internal()

    def some_internal(self):
        return varname(caller = 2)

    def copy(self):
        return self.copy_id()

    def copy_id(self):
        return self.copy_id_internal()

    def copy_id_internal(self):
        return varname(caller = 3)

k = Klass()
# k.id == 'k'

k2 = k.copy()
# k2 == 'k2'

如果检索名称失败

varname的静态索引从0开始,以将变量名称标记为失败。

func = [function()]
# func == ['var_0']
func = function \
    ()
# func == 'var_1'

限制

  • 通话必须以所需格式书写
  • 上下文必须提前估计,尤其是对于带有长参数列表的函数
  • 您必须知道函数/类将在哪个堆栈中调用
  • 出于性能考虑,由于涉及检查,因此更好地缓存名称

答案 19 :(得分:1)

也许这可能有用:

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

该函数遍历全局作用域中值的ID列表(可以编辑名称空间),根据其ID查找所需/所需的var或函数的索引,然后从以下列表中返回名称:基于获取的索引的全局名称。

答案 20 :(得分:1)

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

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

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

答案 21 :(得分:1)

如果目标是帮助您跟踪变量,则可以编写一个简单的函数来标记变量并返回其值和类型。例如,假设i_f = 3.01,然后将其四舍五入为一个名为i_n的整数以在代码中使用,然后需要一个字符串i_s并将其输入报告中。

def whatis(string, x):
    print(string+' value=',repr(x),type(x))
    return string+' value='+repr(x)+repr(type(x))
i_f=3.01
i_n=int(i_f)
i_s=str(i_n)
i_l=[i_f, i_n, i_s]
i_u=(i_f, i_n, i_s)

## make report that identifies all types
report='\n'+20*'#'+'\nThis is the report:\n'
report+= whatis('i_f ',i_f)+'\n'
report+=whatis('i_n ',i_n)+'\n'
report+=whatis('i_s ',i_s)+'\n'
report+=whatis('i_l ',i_l)+'\n'
report+=whatis('i_u ',i_u)+'\n'
print(report)

这将在每次调用时打印到窗口以进行调试,并为书面报告生成一个字符串。唯一的缺点是,每次调用该函数时,必须两次键入该变量。

我是Python的新手,发现这种非常有用的方式可以记录我在编程时的工作并尝试处理Python中的所有对象。一个缺点是,如果whatis()调用在使用它的过程之外描述的函数,则它将失败。例如,int(i_f)是有效的函数调用,仅因为 int 函数是Python已知的。您可以使用int(i_f ** 2)调用whatis(),但是如果出于某种奇怪的原因而选择定义一个名为int_squared的函数,则必须在使用whatis()的过程中声明它。

答案 22 :(得分:0)

您可以尝试以下操作来检索所定义函数的名称(尽管不适用于内置函数):

import re
def retrieve_name(func):
    return re.match("<function\s+(\w+)\s+at.*", str(func)).group(1)

def foo(x):
    return x**2

print(retrieve_name(foo))
# foo

答案 23 :(得分:0)

我尝试从本地检查人员那里获取名称,但是它无法处理像a [1],b.val这样的var。 之后,我有了一个新主意---从代码中获取var名称,然后尝试使用succ! 如下代码:

#direct get from called function code
def retrieve_name_ex(var):
    stacks = inspect.stack()
    try:
        func = stacks[0].function
        code = stacks[1].code_context[0]
        s = code.index(func)
        s = code.index("(", s + len(func)) + 1
        e = code.index(")", s)
        return code[s:e].strip()
    except:
        return ""

答案 24 :(得分:0)

当从变量的值中找到变量的名称时,
您可能有多个变量等于相同的值,
例如 var1 = 'hello' 和 var2 = 'hello'。

我的解决方案:

def find_var_name(val):

    dict_list = []
    global_dict = dict(globals())

    for k, v in global_dict.items():
        dict_list.append([k, v])
   
    return [item[0] for item in dict_list if item[1] == val]

var1 = 'hello'
var2 = 'hello'
find_var_name('hello')

输出

['var1', 'var2']

答案 25 :(得分:0)

对于常量,您可以使用枚举,它支持检索其名称。

相关问题