Python骚操作之动态定义函数


Posted in Python onMarch 26, 2019

在 Python 中,没有可以在运行时简化函数定义的语法糖。然而,这并不意味着它就不可能,或者是难以实现。

from types import FunctionType

foo_code = compile('def foo(): return "bar"', "<string>", "exec")
foo_func = FunctionType(foo_code.co_consts[0], globals(), "foo")

print(foo_func())

输出:bar

剖析

逐行检视代码,你会发现语言/解释器的屏障是多么脆弱。

>>> from types import FunctionType

Python 文档通常不会列出那些非用于手动创建的类的特征(这是完全合理的)。有三种方法可以解决这个问题:help()、inspect(无法查看内置方法)、以及最后的解决方案,即查看 CPython 源代码。

在本例中,help() 与 inspect 都可以完成工作,但是查看实际的源代码,则会揭示出关于数据类型的更多细节。

>>> from inspect import signature
>>> signature(FunctionType)
<Signature (code, globals, name=None, argdefs=None, closure=None)>

1. code

内部是一个PyCodeobject,作为types.CodeType对外开放。非内置方法拥有一个__code__属性,该属性保存了相应的代码对象。利用内置 compile() 方法,可以在运行期创建types.CodeType对象。

2. globals

如果一个函数引用的变量不是在局部定义的,而是作为参数转入、由默认参数值提供、或者通过闭包上下文提供,则它会在 globals 字典中查找。

内置的 globals() 方法会返回一个对当前模块的全局符号表(global symbol table)的引用 ,因此能被用来提供一个总是与当前表的状态相一致的字典。传入任意其它的字典也是可以的(FunctionType((lambda: bar).__code__, {"bar" : "baz"}, "foo")() == "baz")。

3. name(可选)

控制所返回的函数的__name__ 属性。只真正对 lambdas 有用(由于匿名性,它们通常没有名称),并且重命名函数。

4. argdefs(可选)

通过传入一个包含任意类型的对象的元组,提供一个方式来供应默认参数值(def foo(bar="baz"))。(FunctionType((lambda bar: bar).__code__, {}, "foo", (10,))() == 10)。

5. closure(可选)

(如果需要在 CPython(PyPy,Jython,…)以外的其它 Python VM 中执行,可能不应该触及,因为它严重地依赖于实现细节)。

一个cell 对象的元组。创建 cell 对象并非完全是直截了当的,因为需要调用 CPython 的内部组件,但有一个库可以令它更加方便:exalt(无耻的广告)。(译注:这个库是作者开发的。)

>>> foo_code = compile('def foo(): return "bar"', "<string>", "exec")

compile() 是一个内置方法,因此同时也是文档丰富的。

exec 模式被用到,因为定义函数需用多个语句。

>>> foo_func = FunctionType(foo_code.co_consts[0], globals(), "foo")

聚合全部内容,并将动态创建的函数指定给一个变量。

那个被前一句代码编译成的函数,成为了生成的代码对象的第一个常量,因此仅仅指向 foo_code 是不充分的。这是 exec 模式的直接后果,因为生成的代码对象可以包含多个常量。

>>> print(foo_func())

动态生成的函数可以像其它函数一样被调用。

结尾

除了做实验,需要用到动态创建函数的场景很少。

玩耍(Toying around) Python 的内部构件是一种深入学习这门语言的好方法。

如果需要,可以毫不费力地越过解释器/语言的界线。

还是一如既往地:不要滥用语言 (好吧,一点点也无妨,对吧?)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python基于mysql实现的简单队列以及跨进程锁实例详解
Jul 07 Python
构建Python包的五个简单准则简介
Jun 15 Python
python模拟Django框架实例
May 17 Python
python 3.6 +pyMysql 操作mysql数据库(实例讲解)
Dec 20 Python
pandas中的series数据类型详解
Jul 06 Python
django创建最简单HTML页面跳转方法
Aug 16 Python
Python多线程爬取豆瓣影评API接口
Oct 22 Python
TensorFlow tensor的拼接实例
Jan 19 Python
利用Python裁切tiff图像且读取tiff,shp文件的实例
Mar 10 Python
Django查询优化及ajax编码格式原理解析
Mar 25 Python
基于pytorch中的Sequential用法说明
Jun 24 Python
基于Python实现天天酷跑功能
Jan 06 Python
python 将有序数组转换为二叉树的方法
Mar 26 #Python
浅谈Python爬虫基本套路
Mar 25 #Python
我用Python抓取了7000 多本电子书案例详解
Mar 25 #Python
详解python:time模块用法
Mar 25 #Python
Python minidom模块用法示例【DOM写入和解析XML】
Mar 25 #Python
Python实例方法、类方法、静态方法的区别与作用详解
Mar 25 #Python
详解Python装饰器
Mar 25 #Python
You might like
微盾PHP脚本加密专家php解密算法
2020/09/13 PHP
php中用数组的方法设置cookies
2011/04/21 PHP
探讨fckeditor在Php中的配置详解
2013/06/08 PHP
php根据用户名和手机号查询是否存在手机号码
2017/02/16 PHP
PHP微信H5支付开发实例
2018/07/25 PHP
PHP简单验证码功能机制实例详解
2019/03/27 PHP
Yii2使用Bootbox插件实现自定义弹窗
2015/04/02 Javascript
js实现简单锁屏功能实例
2015/05/27 Javascript
Bootstrap每天必学之导航
2015/11/26 Javascript
Javascript HTML5 Canvas实现的一个画板
2020/04/12 Javascript
Node.js的Koa框架上手及MySQL操作指南
2016/06/13 Javascript
Angular中使用ui router实现系统权限控制及开发遇到问题
2016/09/23 Javascript
javascript十六进制数字和ASCII字符之间的转换方法
2016/12/27 Javascript
浅谈 Vue v-model指令的实现原理
2017/06/08 Javascript
关于react中组件通信的几种方式详解
2017/12/10 Javascript
layui使用form表单实现post请求页面跳转的方法
2019/09/14 Javascript
[04:26]DOTA2上海特锦赛小组赛第二日 TOP10精彩集锦
2016/02/27 DOTA
Python3中的真除和Floor除法用法分析
2016/03/16 Python
Python中字符串的修改及传参详解
2016/11/30 Python
Python简单的制作图片验证码实例
2017/05/31 Python
python matplotlib坐标轴设置的方法
2017/12/05 Python
python 将字符串转换成字典dict的各种方式总结
2018/03/23 Python
解决已经安装requests,却依然提示No module named requests问题
2018/05/18 Python
Python使用pickle模块实现序列化功能示例
2018/07/13 Python
Pytorch提取模型特征向量保存至csv的例子
2020/01/03 Python
Python虚拟环境库virtualenvwrapper安装及使用
2020/06/17 Python
使用python实现下载我们想听的歌曲,速度超快
2020/07/09 Python
python+pygame实现坦克大战小游戏的示例代码(可以自定义子弹速度)
2020/08/11 Python
香港个人化生活购物网站:Ballyhoo Limited
2016/09/10 全球购物
一家外企的面试题目(C/C++面试题,C语言面试题)
2014/03/24 面试题
小学生自我鉴定
2013/10/12 职场文书
计算机毕业大学生推荐信
2013/12/01 职场文书
大四优秀党员个人民主评议
2014/09/19 职场文书
银行实习推荐信
2015/03/27 职场文书
2016年父亲节寄语
2015/12/04 职场文书
Pytest之测试命名规则的使用
2021/04/16 Python