最近在做编译原理课程设计,在实现基于DAG的局部优化算法时需要生成很多变量且变量需要以n1、n2、n3····n100这种形式命名作为DAG结点的编码,使用其他静态编译语言据我了解只能在代码中手动写出这100个变量名,但是查阅资料发现Python能够实现动态生成变量名而不像静态语言一样笨拙。
解决动态生成变量名的问题有几种方法,类似locals
函数、exec
函数。其中我选择的是exec
函数,选择的原因是这两个函数起先我都不了解,于是尝试写一些demo学习使用它们,然而locals
函数好像在我的应用场景中并不适用又或者是由于我的使用方法不对导致的无法得到想要的结果,诸多原因使得我最终选择了exec
函数来动态生成变量名。
单独使用exec
函数其实并不能动态生成变量名,与format
函数加以配合才能达到该目的。
exec函数
这里首先介绍一下exec
函数。exec
函数是Python的built-in函数(内置函数)。exec
函数的实际作用是动态执行Python代码。也就是说exec
函数可以执行复杂的Python代码。
1 | exec(source, globals=None, locals=None, /) |
参数说明:
- source:必选参数,表示需要被指定的Python代码。它必须是字符串或者code对象。如果
source
是一个字符串,该字符串会先被解析为一组Python语句,然后执行。如果source
是code对象,那么它只是被简单的执行。 - globals:可选参数,表示全局命名空间(存放全局变量),如果被提供,则必须是一个字典对象。
- locals:可选参数,表示局部命名空间(存放局部变量),如果被提供,可以是任何映射对象。如果参数被忽略,那么它将会取与
globals
相同的值。
如果globals
和locals
都被忽略,那么它们将取exec
函数被调用环境下的全局命名空间和局部命名空间。
返回值:exec
函数的返回值永远为None
。
示例:1
2
3
4
52 i =
3 j =
"ans = i + j") exec(
"Answer is: ", ans) print(
Answer is: 5
解释一下在上个例子中,ans
变量并没有显式的定义,但仍然可以在print
函数中调用。这是由于exec()
语句执行了"ans = i + j"
中的代码,定义了ans
变量。
format函数
str.format
函数是一种格式化字符串的函数,它增强了字符串格式化的功能。
基本语法是通过{}
和:
来代替之前的%
。format
函数可以接受不限个参数,位置可以不按顺序。
示例:1
2
3
4>>>"{} {}".format("hello", "world") # 不设置指定位置,按默认顺序
'hello world'
>>>"{1} {0} {1}".format("hello", "world") # 设置指定位置
'world hello world'
同样可以设置参数:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#!/usr/bin/python
# -*- coding: UTF-8 -*-
"网站名:{name}, 地址 {url}".format(name="菜鸟教程", url="www.runoob.com")) print(
网站名:菜鸟教程, 地址 www.runoob.com
# 通过字典设置参数
"name": "菜鸟教程", "url": "www.runoob.com"} site = {
"网站名:{name}, 地址 {url}".format(**site)) print(
网站名:菜鸟教程, 地址 www.runoob.com
# 通过列表索引设置参数
'菜鸟教程', 'www.runoob.com'] my_list = [
"网站名:{0[0]}, 地址 {0[1]}".format(my_list)) # "0" 是必须的 print(
网站名:菜鸟教程, 地址 www.runoob.com
也可以向str.format()
传入对象:1
2
3
4
5
6
7
8#!/usr/bin/python
# -*- coding: UTF-8 -*-
class AssignValue(object):
def __init__(self, value):
self.value = value
my_value = AssignValue(6)
print('value 为: {0.value}'.format(my_value)) # "0" 是可选的
输出结果为:1
value 为: 6
菜鸟教程中还有一些数字格式化的具体教程,感兴趣的可以看一下。
动态生成变量名
将上述介绍的exec
函数和format
函数结合起来就能够做到动态生成变量名。
示例:1
2
3
4
5
6In [1]: for i in range(5):
...: exec('var{} = {}'.format(i, i))
...:
In [2]: print(var0, var1, var2, var3 ,var4)
0 1 2 3 4
eval函数
eval
函数与exec
函数有些相似但又有些不同exec
,所以这里同时介绍eval
函数,与exec
函数对比记忆加深理解。eval
函数同样能够做到动态执行代码,但是它所能够执行的代码相比exec
函数有特殊的限定。
eval
函数的实际作用是计算指定表达式的值。也就是说它要执行的Python代码只能是单个表达式(注意eval
不支持任何形式的赋值操作),而不能是复杂的代码逻辑。
1 | eval(source, globals=None, locals=None, /) |
参数说明与exec
函数的一样。
返回值:
如果source
是一个code对象,且创建该code对象时,complie
函数的mode参数是exec
,那么eval
函数的返回值是None;
否则,如果source
是一个输出语句,如print()
,则eval()
的返回结果为None
;
否则,source
表达式的结果就是eval()
的返回值。
示例:1
2
3
4
5
6
7
8
9
10
11
12x = 10
def func():
y = 20 #局部变量y
a = eval("x+y")
print("a:",a) #x没有就调用全局变量
b = eval("x+y",{"x":1,"y":2}) #定义局部变量,优先调用
print("b:",b)
c = eval("x+y",{"x":1,"y":2},{"y":3,"z":4})
print("c:",c)
d = eval("print(x,y)")
print("d:",d) #对于变量d,因为print()函数不是一个计算表达式,因此没有返回值
func()
输出结果:1
2
3
4
5a: 30
b: 3
c: 4
10 20
d: None
eval函数和exec函数的区别
eval
函数只能计算单个表达式的值,而exec
函数可以动态运行代码段;eval
函数可以有返回值,而exec
函数返回值永远为None
;
参考资料
Python动态变量名定义与调用 - Pyerlife - 博客园
python中的exec()、eval()以及complie() - 明王不动心 - 博客园
Python format 格式化函数 | 菜鸟教程