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() 的安全用法……

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

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

(0)

相关推荐

  • Python判断变量名是否合法的方法示例

    问题: 变量名是否合法: 1.变量名可以由字母,数字或者下划线组成 2.变量名只能以字母或者下划线开头 s = 'hello@' 判断变量名的第一个元素是否为字母或者下划线 s[0] 如果第一个元素符合条件,判断除了第一个元素之外的其他元素s[1:] 思路: 1.变量名的第一个字符是否为字母或下划线 2.如果是,继续判断 --> 4 3.如果不是,报错 4.依次判断除了第一个字符之外的其他字符 5.判断是否为字母数字或者下划线 while True: s = input('变量名:') #定义退

  • Python变量类型知识点总结

    变量存储在内存中的值.这就意味着在创建变量时会在内存中开辟一个空间. 基于变量的数据类型,解释器会分配指定内存,并决定什么数据可以被存储在内存中. 因此,变量可以指定不同的数据类型,这些变量可以存储整数,小数或字符. 变量赋值 Python 中的变量赋值不需要类型声明. 每个变量在内存中创建,都包括变量的标识,名称和数据这些信息. 每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建. 等号(=)用来给变量赋值. 等号(=)运算符左边是一个变量名,等号(=)运算符右边是存储在变量中的值.例如

  • 在python中对变量判断是否为None的三种方法总结

    三种主要的写法有: 第一种:if X is None; 第二种:if not X: 当X为None,  False, 空字符串"", 0, 空列表[], 空字典{}, 空元组()这些时,not X为真,即无法分辨出他们之间的不同. 第三种:if not X is None; 在Python中,None.空列表[].空字典{}.空元组().0等一系列代表空和无的对象会被转换成False.除此之外的其它对象都会被转化成True. 在命令if not 1中,1便会转换为bool类型的True

  • 在Python 中同一个类两个函数间变量的调用方法

    如下所示: class A(): def test_a(self): self.m ="hello" def test_b(self): self.test_a() n=self.m + "world" print(n) if __name__ == '__main__': A().test_b() 运行结果: 以上这篇在Python 中同一个类两个函数间变量的调用方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • python 通过类中一个方法获取另一个方法变量的实例

    1.在进行接口自动化测试过程中,经常出现接口数据的互相调用,如一些操作需要调用登陆之后返回的session或者token,下面同个简单的方法进行讲解 class A(): def a_add_b(self): a=10 b=20 self.S=a+b print (self.S) return self.S def c_add_ab(self): c=30 s=c+self.S print (s) t=A() t.a_add_b() t.c_add_ab() 运行之后,打印的结果为 30 60

  • Python面向对象程序设计中类的定义、实例化、封装及私有变量/方法详解

    本文实例讲述了Python面向对象程序设计中类的定义.实例化.封装及私有变量/方法.分享给大家供大家参考,具体如下: 1. 定义类 python中定义一个类的格式如下: class MyClass(object): def __init__(self,data1,data2): self.__data1=data1 self.data2=data2 def __func1(self): print("MyClass类的私有方法被调用!") def print_data(self): s

  • 浅谈python函数调用返回两个或多个变量的方法

    以元祖形式返回  return (a,b,......) 以元祖引用或(x,y,....)接受都可以 为什么不能用列表返回?? 与java一样,列表等属于可变数据类型--由指针指向数据本身. 如果返回列表,其实质是返回列表引用,列表引用本可以找到数据本身,但由于回收机制,数据本身很可能已经被回收了,所以用列表返回并不可行 ===========update========== python中用列表也可以....奇怪! 以上这篇浅谈python函数调用返回两个或多个变量的方法就是小编分享给大家的全

  • Python将字符串常量转化为变量方法总结

    前几天,我们Python猫交流学习群 里的 M 同学提了个问题.这个问题挺有意思,经初次讨论,我们认为它无解. 然而,我认为它很有价值,应该继续思考怎么解决,所以就在私密的知识星球上记录了下来. 万万没想到的是,在第二天,有两位同学接连给出了解决方法! 由此,群内出现了一轮热烈的技术交流. 本文将相关的内容要点作了梳理,并由此引申到更进一步的学习话题,希望对你有所帮助. 1.如何动态生成变量名? M 同学的问题如下: 打扰一下大家,请教一个问题,已知 list = ['A', 'B', 'C',

  • Python 存储字符串时节省空间的方法

    从 Python 3 开始,str 类型代表着 Unicode 字符串.取决于编码的类型,一个 Unicode 字符可能会占 4 个字节,这个有些时候有点浪费内存. 出于内存占用以及性能方面的考虑,Python 内部采用下面 3 种方式来存储 Unicode 字符: 一个字符占一个字节(Latin-1 编码) 一个字符占二个字节(UCS-2 编码) 一个字符占四个字节(UCS-4 编码) 使用 Python 进行开发的时候,我们会觉得字符串的处理都很类似,很多时候根本不需要注意这些差别.可是,当

  • python判断字符串是否是json格式方法分享

    在实际工作中,有时候需要对判断字符串是否为合法的json格式 解决方法使用json.loads,这样更加符合'Pythonic'写法 代码示例: Python import json def is_json(myjson): try: json_object = json.loads(myjson) except ValueError, e: return False return True 运行代码编辑模式复制折叠 输出结果: Python print is_json("{}") #

  • python中字符串String及其常见操作指南(方法、函数)

    目录 下标与切片 常见方法 查找 替换 分割 大小写格式化 对齐格式化 清除空白字符 检查 补充:16个常用函数 总结 注意:对字符串的所有操作,原始数据(即原字符串)不变 !(字符串是不可变类型) 对原字符串操作会返回一个操作后的数据, 可以使用变量去接受数据 ----------------------------------------------------------------------------------------------------------------------

  • python将字符串转换成数组的方法

    python将字符串转换成数组的方法.分享给大家供大家参考.具体实现方法如下: #----------------------------------------- # Name: string_to_array.py # Author: Kevin Harris # Last Modified: 02/13/04 # Description: This Python script demonstrates # how to modify a string by # converting it

  • python判断字符串是否纯数字的方法

    本文实例讲述了python判断字符串是否纯数字的方法.分享给大家供大家参考.具体如下: 判断的代码如下,通过异常判断不能区分前面带正负号的区别,正则表达式可以根据自己需要比较灵活的写,通过isdigit方法用来判断是否是纯数字,测试代码如下 复制代码 代码如下: #!/usr/bin/python # -*- coding: utf-8 -*- a = "1" b = "1.2" c = "a" #通过抛出异常 def is_num_by_exc

  • python清除字符串里非数字字符的方法

    本文实例讲述了python清除字符串里非数字字符的方法.分享给大家供大家参考.具体如下: import re s = "how19 a*re 254y**ou?" # Using regular expressions print re.sub("\D", "", s) 希望本文所述对大家的Python程序设计有所帮助.

  • python实现字符串和日期相互转换的方法

    本文实例讲述了python实现字符串和日期相互转换的方法.分享给大家供大家参考.具体分析如下: 这里用的分别是time和datetime函数 ''' @author: jiangqh ''' import time,datetime # date to str print time.strftime("%Y-%m-%d %X", time.localtime()) #str to date t = time.strptime("2009 - 08 - 08", &q

  • 对python 匹配字符串开头和结尾的方法详解

    1.你需要通过指定的文本模式去检查字符串的开头或者结尾,比如文件名后缀,URL Scheme 等等.检 查 字 符 串 开 头 或 结 尾 的 一 个 简 单 方 法 是 使 用str.startswith() 或 者 是str.endswith()方法.比如: >>> filename = 'spam.txt' >>> filename.endswith('.txt') True >>> filename.startswith('file:') Fa

  • python 将字符串完成特定的向右移动方法

    # 将字符串中的元素完成特定的向右移动,参数:字符串.移动长度 如:abcdef,移动2,结果:efabcd #原始方法,基本思想:末尾元素移动到开头,其他的元素依次向后移动.代码如下: def move(lt, n): lt = list(lt) #将字符串转换为列表 for i in range(n % len(lt)):#确定移动几次,比如说移动从长度和列表的长度相同时,就没必要移动 t = lt[len(lt) - 1] #取出末尾元素 for j in reversed(range(l

随机推荐