python输出变量名-python:以字符串形式获取变量名

这个线程讨论了如何在Python中以字符串的形式获取函数名:如何在Python中获得函数名作为字符串?

如何对变量做同样的处理呢?(注意Python变量没有属性__name__,至少在Python中没有属性2.7.x)

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

1

2foo = dict()

foo["bar"] = 2

我正在寻找一个函数/属性,例如retrieve_name:

1retrieve_name(foo)

返回字符串"foo"

更新:

既然人们问我为什么要这么做,这里有一个例子。我想在panda中从这个列表创建一个DataFrame,其中列名由实际字典的名称给出:

1

2# List of dictionaries for my DataFrame

list_of_dicts = [n_jobs, users, queues, priorities]

你为什么要这么做?

在什么情况下retrieve_name(x)不能被"x"作为硬编码字符串替换?

@DavidRobinson。我只是举了个例子

可能的python副本获取函数中参数的变量名

是否可以用Python打印原始变量的名称?

可能复制如何在python中以字符串形式获取变量名

这个家伙从c#中模仿了nameof的行为。

我之所以要这样做,是因为我想编写一个函数,将给定变量的名称和类型打印到调试日志中。

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

如果不递归遍历命名对象树,您想要做的是不可能的;名称是对对象的单向引用。常见的或普通的Python对象不包含对其名称的引用。想象一下,如果每个整数、每个dict、每个列表、每个布尔值都需要维护一个表示引用它的名称的字符串列表!这将是一个实现噩梦,对程序员没有什么好处。

谢谢。但是为什么Python要对函数这样做呢?(即Python对象的一种类型)

所以错误消息是有意义的。

不要忘记模块:它们也有规范的名称。此外,不要忘记__name__总是可以修改的,这意味着"规范"名称可能不是一个可以用来获取对象的名称(例如,当动态创建类时)。

@nneonneo,谢谢,这是我的答案!

正如@scohe001所示,你的"这根本不可能"是错误的。Python的变量名数据库就像任何其他关系数据库一样,您总是可以"反向"搜索相关对象,并返回第一个找到的或任何给定变量的所有有效变量名。

@hobs你在技术上是正确的…最好的一种正确。然而,在实践中,对象有太多的潜在名称,因此获取这些名称的麻烦要比获取它们的价值大得多。

如果你的"值得"门槛是O(1),我想你是对的。scohe001的循环是O(N)

对象可以是列表、字典或其他容器的成员,也可以是对象属性……那么在这种情况下,您还需要找到包含对象的名称……这也可能被另一个物体所包含…因此,您可能需要递归地查找名称,直到找到当前代码可以找到的对象为止。这看起来像是编写和调试许多容易出错的代码,但没有什么好处。

我相信@scohe001会感谢您将他的"可能性"链接到您的"不可能"断言附近,甚至纠正它,因为他提供的可能性是正确的、简单的,并且提供了OP需要的东西(globals() root中的var),我将其解释为"好处",这确实是值得的。

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

有人在回答中提到,您可能需要遍历堆栈并检查每个人的局部变量和全局变量来找到foo,但是如果在调用这个retrieve_name函数的范围内分配了foo,那么您可以使用inspect的current frame来获得所有这些局部变量。

我的解释可能有点太啰嗦了(也许我应该少用"foo"这个词),但这是它在代码中的样子(注意,如果有多个变量分配给相同的值,您将得到这两个变量的名称):

1

2

3

4

5

6

7

8

9import 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)

如果你从另一个函数调用这个函数,比如:

1

2

3

4def foo(bar):

return retrieve_name(bar)

foo(baz)

您想要的是baz而不是bar,您只需要进一步返回一个作用域。这可以通过在caller_local_vars初始化中添加额外的.f_back来实现。

这里有一个例子:ideone

这样就行了。那就是说:这根本不应该做

@theodox我完全同意,因为这可能会对import hooks、ironpython和jython产生影响。

这是行不通的。原子变量没有将其名称作为属性。因此,如果您有a, b = 2, 2, retrieve_name(a)和retrieve_name(b)都将返回["a", "b"]或["b", "a"]

@tomas实际上,这是cPython优化的一个实现细节,其中255以下的整数基本上是单例的,因此任何赋值的变量都将有效地返回true进行is比较

这应该是正确答案。

是否有一个mod来获取传递的var的名称?例如:def foo(bar): retrieve_name(bar)总是返回bar,但是如果您想要foo(baz)返回baz)而不是bar呢?

@SumNeuron只需要修改赋值callers_local_vars的行,使其返回一个范围,这样它就可以查看调用foo的对象的范围。将行更改为inspect.currentframe().f_back.f_back.f_locals.items()(注意额外的f_back)。

我不相信这是可能的。考虑下面的例子:

1

2

3

4

5

6>>> a = []

>>> b = a

>>> id(a)

140031712435664

>>> id(b)

140031712435664

a和b指向同一个对象,但是对象不知道哪个变量指向它。

当然,可以通过扩展引用计数来实现双向关系。这个答案(以及其他一些答案)甚至提供了一个实现。

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

1

2

3

4

5

6

7

8

9

10

11

12

13import 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]

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

不错的工作!虽然我试了一下,但是没有成功。你能在这方面提供进一步的帮助吗?

这与布尔变量有关。最后得到stop_on_error

1

2def name(**variables):

return [x for x in variables]

它的用法是这样的:

1name(variable=variable)

这将不会返回所需变量的名称,而是"变量"。例如-使用name(variable=variable)将输出["variable"],而使用name(variable=another_variable)将输出["another_variable"]而不是["variable"]。

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

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

1

2

3

4x = "foo"

y = "bar"

d = autodict(x, y)

print d

将:

1{"x": "foo", "y": "bar"}

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

无论如何,代码如下:

1

2

3

4

5

6

7

8

9

10

11def autodict(*args):

get_rid_of = ["autodict(", ",", ")", "

"]

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的字符串。

这种魔术的明显缺点是,它对源代码的结构进行了假设。当然,如果它在解释器中运行,它根本就不能工作。

我写了包魔法来强力地做这种魔法。你可以写:

1

2

3from sorcery import dict_of

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

并将其传递给dataframe构造函数。等价于:

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

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

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

Python不会将赋值左侧的名称保存到赋值对象中,因为:它需要在多个相互冲突的对象中找出哪个名称是"规范的",对于从未赋值给显式变量名的对象,这将是非常低效的,实际上,没有其他语言能做到这一点。

因此,例如,使用lambda定义的函数总是具有"名称",而不是特定的函数名称。

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

我认为在Python中做到这一点非常困难,因为一个简单的事实是,您永远不会不知道正在使用的变量的名称。所以,在他的例子中,你可以这样做:

而不是:

1

2

3list_of_dicts = [n_jobs, users, queues, priorities]

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

1

2

3

4>>> locals()["foo"]

{}

>>> globals()["foo"]

{}

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

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

如果名称在调用方框架中,该怎么办?然后你不得不做一些傻事,比如遍历堆栈并检查每个人的locals和globals……如果名字不存在,你就有可能把它弄错。这是一大堆没有实际有用收益的工作。

整个问题都很愚蠢……但如果这是他想做的,那是可能的。至于检查存在性,可以使用Globals()。setdefault(var, 我不确定他到底想要什么,但也许了解到变量是按范围保存的,他就能找到更好的方法。

这个函数将打印变量名及其值:

1

2

3def 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))

1

2

3

4

5

6

7***Input & Function call:***

my_var = 10

print_this(my_var)

***Output**:*

my_var: 10

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

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

1

2

3

4

5

6def retrieve_name(x, Vars=vars()):

for k in Vars:

if type(x) == type(Vars[k]):

if x is Vars[k]:

return k

return None

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25def 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="

"+20*"#"+"

This is the report:

"

report+= whatis("i_f ",i_f)+"

"

report+=whatis("i_n ",i_n)+"

"

report+=whatis("i_s ",i_s)+"

"

report+=whatis("i_l ",i_l)+"

"

report+=whatis("i_u ",i_u)+"

"

print(report)

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

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

我试图从inspect局部变量获得name,但它不能处理像[1],b.val这样的var。在此之后,我有了一个新想法——从代码中获取var name,然后尝试使用succ!下面的代码:

1

2

3

4

5

6

7

8

9

10

11

12#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""

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中,可以使用`vars()`函数来获取一个对象的成员变量的名称和值。引用\[1\]中的示例展示了如何使用`vars()`函数来获取一个类的成员变量的名称和值。例如,如果有一个类`Dummy`,它有成员变量`i`和`j`,可以使用`vars()`函数来获取它们的值。另外,如果有一个对象`dummy`,可以使用`vars()`函数来获取它的成员变量的值。\[1\] 另外,引用\[2\]提到了一个名为`name()`的函数,它可以返回变量的名称。但是需要注意的是,它返回的是变量的名称而不是变量的值。\[2\] 总结来说,如果你想要获取一个字符串的内容变量值,你可以使用`vars()`函数来获取一个对象的成员变量的值。但是如果你想要获取一个变量的名称,你可以使用`name()`函数。请注意,`name()`函数返回的是变量的名称而不是变量的值。\[1\]\[2\] #### 引用[.reference_title] - *1* [python字符串变量名互相转换](https://blog.csdn.net/int_main_Roland/article/details/124506877)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [python输出变量名-python:以字符串形式获取变量名](https://blog.csdn.net/weixin_39928667/article/details/109622521)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值