Python: 将字符串作为变量名 将变量名转为字符串Python: 将字符串作为变量名 将变量名转为字符串Python: 将字符串作为变量名 将变量名转为字符串Python: 将字符串作为变量名 将变量名转为字符串
  • 首页
  • 博客
  • 书签
  • 文件
  • 分析
  • 登录

Python: 将字符串作为变量名 将变量名转为字符串

发表 admin at 2022年8月13日
类别
  • Python
标签
一、Python将字符串作为变量名 

一共三种方法:

    >>> var = "This is a string"
    >>> varName = 'var'
    >>> s= locals()[varName]
    >>> s
    'This is a string'
    >>> s2=vars()[varName]
    >>> s2
    'This is a string'
    >>> s3=eval(varName)
    >>> s3
    'This is a string'

例:
var = "dog"
varName = 'var'

print(var, id(var))  # dog 139970377980848
print(locals()[varName], id(locals()[varName]))  # dog 139970377980848
print(globals()[varName], id(globals()[varName]))  # dog 139970377980848
print(vars()[varName], id(vars()[varName]))  # dog 139970377980848

print('*' * 50)

locals()[varName] = 'cat'

print(var, id(var))  # cat 139970376982768
print(locals()[varName], id(locals()[varName]))  # cat 139970376982768
print(globals()[varName], id(globals()[varName]))  # cat 139970376982768
print(vars()[varName], id(vars()[varName]))  # cat 139970376982768
1. locals()

locals是python的内置函数,他可以以字典的方式去访问局部和全局变量。

python里面用名字空间记录着变量,就像javascript的window一样,他记录着各种全局变量。

每个模块,每个函数都有自己的名字空间,记录着变量,常量,类的命名和值。

就像JS一样,当python在使用变量时,会按照下面的步骤去搜索:

函数或类的局部变量。
全局变量。
内置变量。

以上三个步骤,其中一步骤找到对应的变量,就不会再往下找。如果在这三个步骤都找不到,就会抛出异常。

locals与globals的区别

locals()是只读的。globals()不是。这里说的只读,是值对于原有变量的只读。其实还可以对locals()赋值的。
globals返回的是当前模块的全局变量 locals返回的是局部变量。注意,locals返回的是当前所在最小命名空间的局部变量的一个拷贝。

体检locals

list1 = [1,2,3]
locals()

# 在全局中使用locals,会打印出list1和__builtins__、__name__、__doc__、__package__
复制代码
def foo(args):
x=1
print locals()

foo(123)

#将会得到 {'arg':123,'x':1}

2. vars()

本函数是实现返回对象object的属性和属性值的字典对象。如果默认不输入参数,就打印当前调用位置的属性和属性值,相当于locals()的功能。如果有参数输入,就只打印这个参数相应的属性和属性值。

#vars() 

print(vars()) 

class Foo: 
a = 1 
print(vars(Foo)) 

foo = Foo() 
print(vars(foo)) 

3. eval()

eval()函数十分强大,官方demo解释为:将字符串str当成有效的表达式来求值并返回计算结果。

结合math当成一个计算器很好用。

其他用法,可以把list,tuple,dict和string相互转化。见下例子:

a = "[[1,2], [3,4], [5,6], [7,8], [9,0]]"
b = eval(a)
b
Out[3]: [[1, 2], [3, 4], [5, 6], [7, 8], [9, 0]]
type(b)
Out[4]: list
a = "{1: 'a', 2: 'b'}"
b = eval(a)
b
Out[7]: {1: 'a', 2: 'b'}
type(b)
Out[8]: dict
a = "([1,2], [3,4], [5,6], [7,8], (9,0))"
b = eval(a)
b
Out[11]: ([1, 2], [3, 4], [5, 6], [7, 8], (9, 0))

强大的函数有代价。安全性是其最大的缺点。
想一想这种使用环境:需要用户输入一个表达式,并求值。

如果用户恶意输入,例如:
__import__('os').system('dir')

那么eval()之后,你会发现,当前目录文件都会展现在用户前面。

那么继续输入:
open('文件名').read()

代码都给人看了。获取完毕,一条删除命令,文件消失。哭吧!

怎么避免安全问题?

(1) 自行写检查函数;
(2) 使用ast.literal_eval

eval() 和exec()

区别是eval()有返回值 

def test1():
    print "Test1 Excuted!"
    return True

ret = eval ("test1()")
print ret

结果如下
>>> 
Test1 Excuted!
True

而exec()只执行,并无返回值。

def test2():
    print "Test2 Excuted!"
    return True

exec("test2()")

结果如下
>>> 
Test2 Excuted!
>>>

如果要将exec()赋值,会有以下语法错误!

ret = exec("test2()")

二、Python将变量名转为字符串

程序运行时,其实变量名本身并不重要,更重要的是变量的类型和值

但我们花了很多心思为了考虑可读性而命名的(一长串)变量名,为何不能简单一点取出来呢?

这是一个比较小众的需求,但比较有意思,在网上找了一些方法,都比较零散,本文汇总一下

应用场景可能不多,主要在画图命名子图,或者为pd.DataFrame设置index或column时可能用到

# 先定义测试用的变量,分别是字符串、整型、浮点型、np.array、pd.DataFrame
aa='weqweqw'
bb=4565
cc=546.5
dd=np.array([bb,cc])
ff=pd.DataFrame([dd,dd[::-1]])

# 放到列表里,方便后续在循环中使用
test=[aa,bb,cc,dd,ff]

方法一,需要调用inspect库,有时候会有奇怪的bug,如果一个程序中定义了很多变量,不一定var_name_list的第0个元素就是变量名本身

# 方法一,需要调用inspect库,有时候会有奇怪的bug,如果一个程序中定义了很多变量,不一定var_name_list的第0个元素就是变量名本身
def retrieve_name(var):
    import inspect
    callers_local_vars = inspect.currentframe().f_back.f_locals.items()
    var_name_list = [var_name for var_name, var_val in callers_local_vars if var_val is var] 
    if len(var_name_list) > 0:
        return var_name_list[0]

# 测试方法一
print('方法一')
for i in test:  
    i_name=retrieve_name(i)
    print(i_name,type(i_name),sep='\n') 
    

方法二,变量多时非常容易出bug,且每次使用前都要重新取vk,使用麻烦,本人不推荐

# 方法二,变量多时容易出bug,且每次使用前都要重新取vk,使用麻烦,本人不推荐
vk = {}
p_locals = locals().copy()
for k,v in p_locals.items():
    vk[ id(v) ] = k
def var_name(p,vk):    
    return vk[ id(p) ]

# 测试方法二
print('方法二')
for i in test:    
    i_name=var_name(i,vk)
    print(i_name,type(i_name),sep='\n')

方法三,代码短小,只能现场使用,不能封装函数,也不能写进循环,简单使用可以,大量使用的话略麻烦,花这个工夫不如自己输入了

# 方法三,代码短小,但只能现场使用,不能封装函数,也不能写进循环,大量使用的话略麻烦
aa_name=list(dict(aa=aa).keys())[0]
bb_name=list(dict(bb=bb).keys())[0]    
cc_name=list(dict(cc=cc).keys())[0]  
dd_name=list(dict(dd=dd).keys())[0] 
ff_name=list(dict(ff=ff).keys())[0] 

# 测试方法三
print('方法三',
      aa_name,type(aa_name),
      bb_name,type(bb_name),
      cc_name,type(cc_name),
      dd_name,type(dd_name),
      ff_name,type(ff_name),
      sep='\n')

方法四,先一行匿名函数声明,后面一行代码调用,不容易出bug,个人推荐使用!

# 方法四,匿名函数,先一行代码声明,后面一行代码调用,不容易出bug,推荐使用
vname = lambda v,nms: [ vn for vn in nms if id(v)==id(nms[vn])][0]

# 测试方法四
print('方法四')
for i in test:  
    i_name=vname(i,locals())
    print(i_name,type(i_name),sep='\n')

简单的使用场景下,这几个方法都是没问题的
如果有更简便的方法欢迎交流
祝各位科研顺利~

发表回复 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注

类别

  • Cat
  • Python
  • MySQL
  • Django
  • Html/CSS
  • JavaScript
  • Vue
  • RegExp
  • php
  • Practice
  • Virtualization
  • Linux
  • Windows
  • Android
  • NAS
  • Software
  • Hardware
  • Network
  • Router
  • Office
  • WordPress
  • SEO
  • English
  • Games
  • Recipes
  • living
  • Memorandum
  • Essays
  • 未分类

归档

©2015-2023 艾丽卡 Blog support@alaica.com
      ajax-loader