2019独角兽企业重金招聘Python工程师标准>>>

前几天,我们Python猫交流学习群 里的 M 同学提了个问题。这个问题挺有意思,经初次讨论,我们认为它无解。

然而,我认为它很有价值,应该继续思考怎么解决,所以就在私密的知识星球上记录了下来。

万万没想到的是,在第二天,有两位同学接连给出了解决方法!

由此,群内出现了一轮热烈的技术交流。

本文将相关的内容要点作了梳理,并由此引申到更进一步的学习话题,希望对你有所帮助。

1、如何动态生成变量名?

M 同学的问题如下:

打扰一下大家,请教一个问题,已知 list = ['A', 'B', 'C', 'D'] , 如何才能得到以 list 中元素命名的新列表 A = [], B = [], C = [], D = [] 呢?

简单理解,这个问题的意思是,将字符串内容作为其它对象的变量名。

list 中的元素是字符串,此处的 ‘A’-‘D’ 是常量 ,而在要求的结果中,A-D 是变量

如果强行直接将常量当做变量使用,它会报错:

>>> 'A' = []
...SyntaxError: can't assign to literal

报错中的literal 指的是字面量 ,这是计算机科学中常见的一个概念,用于表达源代码中的固定值。 例如,整数、浮点数、字符串等基本类型,就是字面量。

字面量指的就是一个量本身,可以理解为一种原子性的实体,当然不能再被赋值了。

所以,取出的字符串内容,并不能直接用作变量名,需要另想办法。

有初学者可能会想,list[0] = [] 行不行?当然不行,因为没有出现 A 。那 A = list[0] ,接着 A = [] 呢?那也不行,因为这里的 A 是你凭空定义出来的,而不是从已有条件中生成的。

当时,群里只有两三个同学参与了讨论,我们没想到解决办法。但是,我觉得这个题目很有意思,值得玩味。

因为,如果能解决这个问题,那就意味着可以不作预先定义,而是动态地生成变量名,这不仅能减少给变量取名的麻烦,还实现了自动编码!

可以设想一下未来,人工智能在编写代码的时候,如果能根据已知条件,动态生成变量名,那编写代码的过程不就顺利多了么?(据说,现在已经有人工智能可以编写代码了,不知它在取变量名时,是用的什么方法?)

2、办法总是有的

最近,学习群里蒙混进来了几个打广告的,为此,我决定提高审核门槛,例如,用群里的问题来作个考核。

万万没想到的是,第一个被考核到的 Q 同学,几乎不假思索地就说出了一个解决上述问题的思路。而偏偏就是那么巧 ,几乎在同时,群内的 J 同学给出了另外一个解决方法(他没看到群内的讨论,而是看到了知识星球的记录,才知道这个问题的)。

也就是说,前一晚还以为无解的问题,在第二天竟得到了两种不同的解决方法!

那么,他们的答案是什么呢?

# J 同学的解答
>>> list1 = ['A', 'B', 'C', 'D']
>>> for i in list1:
>>>     globals()[i] = []
>>> A
[]

这个方法通过修改全局命名空间,巧妙地“定义”出了新的变量。globals() 方法取出来的是一个字典,字符串 ‘A’ 是其中一个键值(key),而这个键值恰恰是全局命名空间中的一个变量,这就实现了从常量到变量的转化。

在数据结构层面上,空列表 [] 作为一个值(value)跟它的字符串键值绑定在一起,而在运用层面上,它作为变量内容而跟变量名绑定在一起。

看到这个回答的时候,我就突然想起来了,上个月转载过一篇《Python 动态赋值的陷阱》,讲的正是动态地进行变量赋值 的问题啊!我似乎只关注了 globals() 与 locals() 用法的区别,却没有真正地掌握它们的原初用途。

J 同学说,他正是看了那篇文章,才学得了这个方法。这就有意思了,我分享了一个自己囫囵吞枣的知识,然后它被 J 同学吸收掌握,最后反馈回来解决了我的难题。

我真切地感受到了知识分享的魅力:知识在流动中获得生命,在碰撞中锃亮色泽。

同时,我也真切地明白了一个互助的学习团体的好处:利人者也利己,互助者共同进步。

3、动态执行代码的方法

新进群的 Q 同学,提供了一个不同的答案:

# Q 同学的解答
>>> list1 = ['A', 'B', 'C', 'D']
>>> for i in list1:
>>>     exec(f"{i} = []")
>>> A
[]

他的写法用到了 Python 3.6 才引入的 f-strings 特性,事实上,在较低版本中,也是可以实现的,只需要保证 exec() 方法接收的参数是包含了变量 i 的字符串即可,例如这样写:

# 以下代码可替换上例的第 4 行
exec(i + " = []")
# 或者:
exec("{} = []".format(i))
# 或者:
exec(' '.join([i, '= []']))

这几种写法的区别只是字符串拼接法的区别,关于如何拼接字符串,以及不同方法之间的区别,可参看《详解Python拼接字符串的七种方式》。

Q 同学这个答案的核心在于 exec() 方法,它是内置的,用途是执行储存在字符串或文件中的代码段。

它的基础用法如下:

>>> exec('x = 1 + 2')
>>> x
3# 执行代码段
>>> 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 同学提出了另一种修改命名空间中变量的写法、L 同学提到了 eval() 的意义、eval() 与 exec() 的区别、我查到了为什么要慎用 eval() 、C 与 H 同学提到了 eval() 的安全用法......

虽然,某些话题无法在群聊中充分展开,但是,这些话题知识的延展联系,大大地丰富了本文开头的问题,这一个微小的问题,牵连出来了两个大的知识体系。

最后,真得感谢群内的这些爱学习的优秀的同志们!除了文中提及的,还有一些同学也做了积极贡献,大家都很给力!

相关链接:

《Python 动态赋值的陷阱》

《详解Python拼接字符串的七种方式》

eval()、exec()及其相关函数:https://www.tuicool.com/wx/vEbeumE

公众号【Python猫】, 专注Python技术、数据科学和深度学习,力图创造一个有趣又有用的学习分享平台。本号连载优质的系列文章,有喵星哲学猫系列、Python进阶系列、好书推荐系列、优质英文推荐与翻译等等,欢迎关注哦。PS:后台回复“爱学习”,免费获得一份学习大礼包。

转载于:https://my.oschina.net/u/4051725/blog/3023591

Python进阶:如何将字符串常量转化为变量?相关推荐

  1. python定义符号常量_Python将字符串常量转化为变量方法总结

    前几天,我们Python猫交流学习群 里的 M 同学提了个问题.这个问题挺有意思,经初次讨论,我们认为它无解. 然而,我认为它很有价值,应该继续思考怎么解决,所以就在私密的知识星球上记录了下来. 万万 ...

  2. java键盘输入字符串静态变量_Java 中为什么样在静态方法中可以调用的方法、可以使用的成员变量必须是静态的?老师说字符串常量和静态变量放在data segment中...

    在上一篇文章中,小编为您详细介绍了关于<C字符串以'\0'结尾的问题?为什么样C语言字符串常量可以当做指针>相关知识.本篇中小编将再为您讲解标题Java 中为什么样在静态方法中可以调用的方 ...

  3. 小菜鸟的python进阶之路 ------- 字符串

    字符串 定义方法 字符串的特性 字符串的类型判断(可以补全) 字符串开头和结尾的判断 字符串的操作 1.定义方式 a = 'hello' b = 'what\'s up' c = "what ...

  4. 不要使用字符串常量作为对象锁去同步代码

    2019独角兽企业重金招聘Python工程师标准>>> 使用字符串常量作为锁去同步代码是非常危险的事情.请看下面的一段代码: Foo String LOCK = ;someMetho ...

  5. python进阶10并发之六并行化改造

    原创博客地址:python进阶10并发之六并行化改造 图示变量含义说明: 1个大step中包含3个小step,大step内部的第一步,二步,三步存在依赖关系(就是内部保持顺序执行) a1,b1,c1, ...

  6. 字符串常量和变量是什么?

    以下是字符串常量的解释 变量: 顾名思义,变量是可变的,比如对应到我们的生活中,工资,年龄,身高,体重等,这些都是会改变的,并不是一成不变的,这就是变量. 我们可以这么理解 int n=10: 那么这 ...

  7. str.replace()——Python的“第四”字符串格式

    str.replace(),Python的"第四"字符串格式. [学习的细节是欢悦的历程] Python 官网:https://www.python.org/ Free:大咖免费& ...

  8. C++ 文字常量与常变量

    以下代码编译运行平台是 Windows 64bits+VS2017. 使用 C++ 编程时,经常遇到以下几个概念:常量.文字常量.字面常量.符号常量.字符常量.常变量.字符串常量等,网上的资料描述的不 ...

  9. 面试进阶之字符串常量池

    转载自  面试进阶之字符串常量池 作为最基础的引用数据类型,Java 设计者为 String 提供了字符串常量池以提高其性能,那么字符串常量池的具体原理是什么,我们带着以下三个问题,去理解字符串常量池 ...

最新文章

  1. leecode第二十题(有效的括号)
  2. sm4算法(附源码、测试代码)
  3. linux 进程 setuid,Linux SetUID(SUID)文件特殊权限用法详解
  4. 数据库-查看表-创建表-查询表
  5. java扫描指定package注解_java随笔-扫描使用指定注解的类与方法
  6. 【Vegas2008】7月19日-凉粉的做法
  7. 【java】JVM中Perm区持续上涨问题
  8. php开源qq群,QQ群免IDKEY加群PHP源码
  9. 个人优盘更新涉密计算机病毒库,在涉密计算机和非涉密计算机之间交叉使用优盘、移动硬盘等移动存储介质时,只要及时升级杀毒软件病毒库,就不会造成泄密 - 作业在线问答...
  10. 引入html页面比较,前端页面如何引入公用的页面header和footer
  11. 面向对象的三大特性之多态,封装基础
  12. 浪人下载和浪人文章的漏洞利用
  13. Oracle 闪回特性(Flashback Query、Flashback Table)
  14. STM32(7):中断方式让按键点亮LED
  15. Go语言核心之美 2.1-整数
  16. 徐州php溪谷_ThinkPHP溪谷H5游戏平台系统V3.0完整版源码
  17. python概率计算,python简单脚本之概率计算
  18. 访客管理系统 - 天天访客
  19. 如何用SPSS分析调查问卷和撰写调查报告?【SPSS 064期】
  20. 列表排序并返回索引_Python成为专业人士笔记–List列表

热门文章

  1. Java Web 之Token+Cookie+Session
  2. 【JZOJ3598】【CQOI2014】数三角形
  3. 一、Oracle介绍
  4. 用Sql添加删除字段,判断字段是否存在的方法
  5. 属性页中的ON_UPDATE_COMMAND_UI
  6. Go学习笔记—Channel通道
  7. linux ndk编译so,有的APP NDK 编译的SO文件 无法调用 PackageManager
  8. html5点击按钮出现弹窗 怎么实现_HTML5游戏开发过程中的二三事
  9. 不常见但是有用的 Chrome 调试技巧
  10. 项目管理基础:系统分析相关概念介绍