第6.6节 Python动态执行小结
一、 Python动态执行支持通过输入数据流或文件传入Python源代码串,进行编译后执行,可以通过这种方式扩展Python程序的功能;
二、 动态执行方法可能导致恶意攻击,因此使用时需要限定使用范围,注意安全风险;
三、 如果采用先编译后动态执行的方式,注意编译模式必须与执行模式对应;
四、 动态执行可以指定代码的执行空间,动态执行最好在指定的全局名字空间和局部名字空间中执行:
1. 如果省略了可选参数,代码将在当前范围内执行;
2. 如果提供了 globals 参数,就必须是字典类型,而且会被用作全局和局部变量的名字空间;
3. 如果同时提供了 globals 和 locals 参数,它们分别被用作全局和局部变量的名字空间;
4. 动态执行查找变量时的顺序依次为:局部名字空间->全局名字空间->调用exec或eval的代码执行环境的名字空间;
5. 建议所有动态执行都指定单独的执行空间,以保证动态执行不会无意中损害调用方的环境。
五、 在模块层级(通常是动态执行的调用方),全局和局部变量是相同的字典,内置 globals() 和 locals() 函数各自返回当前的全局和局部字典,因此可以将它们传递给 exec() 的第二个和第三个实参,但实际上与这两个参数不传参效果是一样的,因为不传值用的就是在当前调用方所在模块的空间执行,而这两个函数也是返回当前模块的空间,而在模块层级这两个函数返回的值是一样的。
六、 补充知识
1. 动态执行时,如果执行时指定了全局名字空间或局部名字空间,则可以在执行前通过字典键值访问值的模式给对应变量赋值;
举例:
这个例子中,要编译的表达式字符串为‘x+y’,但在编译代码中没有给x和y赋值,通过全局名字空间给x和y赋值的,计算时就取到了对应变量值。
2. 在启动Python解释器之后,即使没有创建任何的变量或者函数,还是会有许多函数可以使用, 我们把这些函数称为内建常量和内建函数,是因为它们不需要我们程序员作任何定义,在启动Python解释器的时候,会首先加载内建名字空间,内建名字空间有许多名字到对象之间映射,而这些名字其实就是内建函数和常量的名称,对象就是这些内建函数和常量本身。这些名字空间由__builtins__模块中的名字构成;
3. __builtins__:对于动态执行时的全局名字空间字典,如果不包含 __builtins__ 键值,则将为该键插入对内建 builtins 模块字典的引用。因此,在将执行的代码传递给 exec() 之前,可以通过将自己的 __builtins__ 字典插入到 globals 中来控制可以使用哪些内置代码。本点老猿没有深入研究,暂时不展开说明。
七、 例子
1. 动态执行全局空间使用调用方的例子
s='''
person=['张三','李四']
for p in person:
print('name=',p)
while(True):
s=input("I will exit,are you ready(y/n)?")
if s=='Y': break;
if s=='y': break;
'''
exec(s,globals(),locals())
此时执行的语句执行效果与exec(s)的执行效果完全相同,执行后s的值被输入改变。
2. 用eval动态执行实现的cal函数
第五章介绍的的cal函数的例子,如果使用动态执行方法的实现代码会简单许多,具体代码如下:
def cal(number1,number2,*numbers,calmethod='+'):
print('number1=',number1,',number2=',number2,',numbers=',numbers,', calmethod=',calmethod)
calmethod=calmethod.strip()
if len(calmethod)!=1: raise ValueError('运算符必须是+-*/中的一个,分别对应加、减、乘、除')
if '+-*/'.find(calmethod)==-1 :raise ValueError('运算符必须是+-*/中的一个,分别对应加、减、乘、除')
if not isinstance(number1,int): raise TypeError('第1个参数必须为整数')
if not isinstance(number2,int): raise TypeError('第2个参数必须为整数')
s=str(number1)+calmethod+str(number2)
for i,n in enumerate(numbers):
if isinstance(n,int): #判断n是否为整数
s+=calmethod+str(n)
else:raise TypeError('第'+str(i+3)+'个参数必须为整数')
return eval(s)
代码及执行样例截屏如下:
上述代码的实现细节在此不再赘述,相信大家都能明白。
3. 以exec定义的cal函数,所有代码全部存储在字符串codebuff中
>>> codebuff='''
def cal(number1,number2,*numbers,calmethod='+'):
print('number1=',number1,',number2=',number2,',numbers=',numbers,', calmethod=',calmethod)
calmethod=calmethod.strip()
if len(calmethod)!=1: raise ValueError('运算符必须是+-*/中的一个,分别对应加、减、乘、除')
if '+-*/'.find(calmethod)==-1 :raise ValueError('运算符必须是+-*/中的一个,分别对应加、减、乘、除')
if not isinstance(number1,int): raise TypeError('第1个参数必须为整数')
if not isinstance(number2,int): raise TypeError('第2个参数必须为整数')
s=str(number1)+calmethod+str(number2)
for i,n in enumerate(numbers):
if isinstance(n,int): #判断n是否为整数
s+=calmethod+str(n)
else:raise TypeError('第'+str(i+3)+'个参数必须为整数')
return eval(s)
'''
>>> ns={}
>>> exec(codebuff,ns)
>>> ns['cal'](1,2,3,calmethod='+')
number1= 1 ,number2= 2 ,numbers= (3,) , calmethod= +
6
>>> add=ns['cal']
>>> add(1,2,3,calmethod='+')
执行截图:
上面这段代码是将第2个例子全部改成动态代码来实现,第一步将所有函数定义放到字符串codebuff缓冲区中,然后定义一个函数执行的名字空间ns,并通过exec执行函数定义的语句,在ns中就生成了函数定义,该函数可以通过名字空间ns以函数名作为键值获取,获取后可以直接执行函数调用,也可以赋值给一个变量add,再通过变量进行调用。
本节对动态执行方法相关的内容进行了总结,并补充说明了传递的全局名字空间和本地名字空间相关的内容。
老猿Python(https://blog.csdn.net/LaoYuanPython)系列文章用于逐步介绍老猿学习Python后总结的学习经验,这些经验有助于没有接触过Python的程序员可以很容易地进入Python的世界。
欢迎大家批评指正,谢谢大家关注!
第6.6节 Python动态执行小结的更多相关文章
- 第6.3节 Python动态执行之动态编译的compile函数
Python支持动态代码主要三个函数,分别是compile.eval和exec.本节介绍compile函数的语法和相关使用.compile函数用来编译一段字符串的源码,将其编译为字节码或者AST(抽像 ...
- 第6.4节 Python动态表达式计算:eval函数详述
在Python动态执行的函数中,eval是用于执行表达式计算的函数,这个函数用于执行字符串中包含的一个表达式或其编译后对应的代码,不能适用于执行Python语句和完整的代码. 一. 语法 1. ...
- 第6.5节 exec函数:一个自说自话的强大Python动态编译器
在Python动态执行的函数中,exec是用于执行一个字符串内包含的Python源码或其编译后对应的字节码. 一. 语法 1. exec(Code, globals=None, local ...
- 第6.2节 Python特色的动态可执行方法简介
一. 基本概念 动态可执行,是指在代码中通过外部输入或代码嵌入的常量字符串包含代码的方式提供Python代码,要求Python执行这些代码.这样就可以达到开放式运行的效果,提高程序的能力和灵活性 ...
- 第6章 Python中的动态可执行方法 第6.1节 Python代码编译
在介绍动态可执行方法前,本节先介绍一下Python代码编译有关的知识,因为部分内容和动态执行有些关联. 一. Python解释器的功能 Python虽然是解释型语言,但Python代码也是可编译 ...
- 第8.20节 Python中限制动态定义实例属性的白名单:__slots__
一. 引言 按照<第7.10节 Python类中的实例变量定义与使用>.<第7.14节Python类中的实例方法解析>中的介绍,当定义了一个类,并且创建了该类的实例后,可以给该 ...
- python中执行shell命令的几个方法小结(转载)
转载:http://www.jb51.net/article/55327.htm python中执行shell命令的几个方法小结 投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014- ...
- Python之PyFrameObject动态执行环境
Python虚拟机中的执行环境 Python的虚拟机实际上是在模拟操作系统运行可执行文件的过程,首先,我们先来讲一下普通的x86的机器上,可执行文件是以一种什么方式运行的. 图1-1 图1-1所展示的 ...
- 第二百八十七节,MySQL数据库-条件语句、循环语句、动态执行SQL语句
MySQL数据库-条件语句.循环语句.动态执行SQL语句 1.if条件语句 delimiter \\ CREATE PROCEDURE proc_if () BEGIN ; THEN ; ELSEIF ...
随机推荐
- 微信小程序获取普通二维码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- leetcode117:search-rotated-sorted-array
题目描述 给出一个转动过的有序数组,你事先不知道该数组转动了多少 (例如,0 1 2 4 5 6 7可能变为4 5 6 7 0 1 2). 在数组中搜索给出的目标值,如果能在数组中找到,返回它的索引, ...
- Prometheus监控告警浅析
前言 最近有个新项目需要搞一套完整的监控告警系统,我们使用了开源监控告警系统Prometheus:其功能强大,可以很方便对其进行扩展,并且可以安装和使用简单:本文首先介绍Prometheus的整个监控 ...
- Spring笔记(7) - Spring的事件和监听机制
一.背景 事件机制作为一种编程机制,在很多开发语言中都提供了支持,同时许多开源框架的设计中都使用了事件机制,比如SpringFramework. 在 Java 语言中,Java 的事件机制参与者有3种 ...
- ssh连接缓慢的问题分析
之前遇到ssh连接缓慢的问题 一般会检查Server端 /etc/ssh/sshd_config配置文件的两个地方 1.设置UseDNS no 因为我们ssh连接服务器的话 如果UseDNS选项是打开 ...
- gitlab - 解决访问 gitlab 网站出现 502 报错信息的问题
问题背景 访问 gitlab 网站,出现 502 解决方案 先查看运行 gitlab 容器的 id docker ps 运行命令 # 容器里启动服务 docker exec id gitlab-ctl ...
- 处理request信息的ngx_http_process_request
在处理完http的头部信息后 然后在 处理request-body信息ngx_http_process_request-------- -----------ngx_http_process_req ...
- JLC PCB 嘉立创自动确认生产稿,不讲武德?耗子尾汁!!!
首先,开局一张图,嘉立创又不做人的一天.嘉立创不讲武德,耗子尾汁!!! 之前下单,勾选了确定生产稿和不加客编,结果生产稿出来还是给我加了客编.那我出10元的意思何在?让我自己花3元看我花的10元有没有 ...
- 每日理解(一) Spring框架
每日理解 SpringIOC 控制反转 在Java SE中通过new来创建对象.而在Spring中通过容器来控制对象. 所谓的控制包括:对象的创建.初始化.以及销毁.我们有之前的主动控制对象,变为了S ...
- Elementary OS常见软件(TIM、微信、企业微信)安装(二)
前言 最终没忍住还是把开发环境迁移到了Elementary OS上来,这其中也没少折腾,试过Ubuntu 20.04 LTS和deepin V20可以(),deepin真的很不错可能是我的电脑兼容性不 ...