当前位置: 首页 > Linux

高级Python:如何将字符串常量转换为变量?

时间:2023-04-06 04:31:13 Linux

前几天,我们Python猫交流学习群的M同学问了一个问题。这个问题很有意思,经过初步讨论,我们认为没有解决办法。不过我觉得很有价值,应该继续思考如何解决,所以记录在知识的私人星球上。没想到第二天,两个同学相继给出了答案!于是,群里进行了一轮热烈的技术交流。本文将相关内容点进行梳理,并引出进一步的学习专题,希望对您有所帮助。1、如何动态生成变量名?M同学的问题如下:请问,请教一个问题,给定list=['A','B','C','D'],如何得到一个以列表A=[]、B=[]、C=[]、D=[]中的元素?简单理解,这道题的意思是将字符串内容作为其他对象的变量名。列表中的元素是字符串,其中'A'-'D'是常量,在请求的结果中,A-D是变量。如果强行把常量直接当作变量使用,会报错:>>>'A'=[]...SyntaxError:can'tassigntoliteral报错中的literal指的是字面值,这是计算机科学中常见的一个概念,用来表示源代码中的一个固定值。例如,整数、浮点数、字符串等基本类型都是字面量。字面量是指一个量本身,可以理解为一个原子实体,当然不能赋值。所以提取出来的字符串内容不能直接作为变量名,需要另找方法。有的初学者可能会想,list[0]=[]可以吗?当然不是,因为A没有出现。A=list[0]后跟A=[]怎么样?那也不行,因为这里的A是你凭空定义的,不是根据现有条件生成的。当时组里只有两三个同学参与讨论,我们也没有想出解决办法。不过,我觉得这个话题很有意思,值得深思。因为,如果能解决这个问题,就意味着可以动态生成变量名而不是预先定义,这样既减少了变量命名的麻烦,又实现了自动编码!你可以想象未来。人工智能在写代码的时候,如果能根据已知条件动态生成变量名,写代码的过程岂不是顺畅很多?(据说现在已经有人工智能可以写代码了,不知道它用什么方法获取变量名?)2、办法总是有的。所以,我决定提高复习门槛,比如用群里的题来做一个考核。没想到,第一个被考核的同学Q几乎是想都没想就想出了解决上述问题的思路。但是就这么巧,几乎在同一时间,群里的J同学给出了另一种解法(他没有看到群里的讨论,但是看到了知识星球的记录,所以才知道这个问题).也就是说,前一天晚上认为无法解决的问题,第二天就得到了两种不同的解决方案!那么他们的答案是什么?#学生J的答案>>>list1=['A','B','C','D']>>>foriinlist1:>>>globals()[i]=[]>>>TheA[]方法通过修改全局命名空间巧妙地“定义”了新变量。globals()方法取出一个字典,字符串'A'是其中一个键值(key),而这个键值只是全局命名空间中的一个变量,实现了常量到变量的转换。在数据结构层面,空列表[]作为值绑定到它的字符串键,在应用层面,它作为变量内容绑定到变量名。看到这个回答突然想起我上个月转过一篇文章《Python 动态赋值的陷阱》,是讲动态赋值的!我似乎只关注globals()和locals()用法之间的区别,而没有真正掌握它们的原始用途。J同学说是看了那篇文章才学会这个方法的。这下有意思了,我分享了一个自己吞下的知识,然后被J同学吸收和掌握了,最后反馈解决了我的问题。真正感受到知识分享的魅力:知识在流动中获得生命,在碰撞中发光。同时,我也真正体会到了互助学习小组的好处:利人者也利己,互助者共同进步。3.动态执行代码的方法。该组的新成员Q同学提供了不同的答案:#Q同学的答案>>>list1=['A','B','C','D']>>foriinlist1:>>>exec(f"{i}=[]")>>>A[]他的写法使用了Python3.6引入的f-strings特性,其实在低版本中,也是可以实现的,只需要保证exec()方法接收的参数是一个包含变量i的字符串,例如:#下面的代码可以替换上面例子的第四行exec(i+"=[]")#或者:exec("{}=[]".format(i))#or:exec(''.join([i,'=[]']))这些写法的区别仅在于字符串的拼接方法的区别,如何拼接字符串,不同方法的区别,请参考《详解Python拼接字符串的七种方式》。Q同学回答的核心在于exec()方法,该方法是内置的,用于执行存储在字符串或文件中的代码段。它的基本用法如下:>>>exec('x=1+2')>>>x3#执行代码段>>>s=""">>>x=10>>>y=20>>>sum=x+y>>>print(sum)>>>""">>>exec(s)30看完了exec()的用法,我们回过头来看Q的回答。for循环中取出的i是一个字符串,拼接后的字符串经过exec()处理,达到动态写代码的效果。也就是说,由于字符串常量的内容作为有效代码执行,其中的'A'-'D'元素获得了新的身份,成为最终的A-D变量名。这个方法看似很简单,但是因为exec()这??个方法太不常见了,直到Q同学提出来我们才醒悟过来。注意:在Python3中,exec()是内置方法;在Python2中,exec是一个语句(statement),还有一个execfile()方法,两者合起来就成了Python3中的exec()方法。本文使用Python3。4.总结和提炼原题。它实际上问的是“如何将字符串内容用作其他对象的变量名”,更具体地说——“如何将常量转换为变量”。使用直接进行赋值的静态方法是行不通的。两位同学提出的方法都是间接的动态方法:一种是动态给变量赋值,通过修改命名空间插入变量;另一种是动态执行代码,可以说是通过“后门”的方式插入变量。两种方法的目的是一致的,不管是白猫还是黑猫,都抓住了老鼠。这两种方法给我们带来了宝贵的启发。同时,因为他们,群里的小伙伴们也对一些相关的话题进行了分歧的讨论。比如:S同学提出了另一种修改命名空间的方式在namespace中如何写变量,L同学提到了eval()的含义,eval()和exec()的区别,我发现为什么eval()应该是慎用,C同学和H同学都提到了eval()的安全使用…………虽然有些话题在群聊中无法完全展开,但是这些话题的知识延伸联系大大丰富了开头的问题本文。这个小问题牵扯到两大知识体系。最后真的要感谢群里热爱学习的优秀同志们!除了文中提到的,还有一些同学也做出了积极的贡献,大家真棒!相关链接:《Python 动态赋值的陷阱》《详解Python拼接字符串的七种方式》eval()、exec()及相关函数:https://www.tuicool.com/wx/vE...公众号【Python猫】,专注于Python技术、数据科学与深度学习,努力打造一个有趣好用的学习分享平台。本期连载系列精品文章,包括喵星哲学猫系列、Python进阶系列、好书推荐系列、优质英文推荐与翻译等,欢迎关注。PS:后台回复“爱学习”,即可免费获得学习大礼包。