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 strip()函数 介绍
May 24 Python
在Django同1个页面中的多表单处理详解
Jan 25 Python
使用python批量读取word文档并整理关键信息到excel表格的实例
Nov 07 Python
python的pytest框架之命令行参数详解(下)
Jun 27 Python
python3用PIL把图片转换为RGB图片的实例
Jul 04 Python
python如何统计代码运行的时长
Jul 24 Python
Django使用unittest模块进行单元测试过程解析
Aug 02 Python
pycharm创建scrapy项目教程及遇到的坑解析
Aug 15 Python
python监控nginx端口和进程状态
Sep 06 Python
Python 正则表达式爬虫使用案例解析
Sep 23 Python
jupyter notebook 恢复误删单元格或者历史代码的实现
Apr 17 Python
使用pandas实现筛选出指定列值所对应的行
Dec 13 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
77A一级收信机修理记
2021/03/02 无线电
真正的ZIP文件操作类(php)
2007/07/21 PHP
php使用cookie实现记住用户名和密码实现代码
2015/04/27 PHP
给WordPress中的留言加上楼层号的PHP代码实例
2015/12/14 PHP
PHP里面把16进制的图片数据显示在html的img标签上(实现方法)
2017/05/02 PHP
php将html转为图片的实现方法
2017/05/19 PHP
javascript设置页面背景色及背景图片的方法
2015/12/29 Javascript
Vue computed计算属性的使用方法
2017/07/14 Javascript
webpack构建vue项目的详细教程(配置篇)
2017/07/17 Javascript
关于Vue.nextTick()的正确使用方法浅析
2017/08/25 Javascript
捕获未处理的Promise错误方法
2017/10/13 Javascript
Nodejs连接mysql并实现增、删、改、查操作的方法详解
2018/01/04 NodeJs
详解如何使用babel进行es6文件的编译
2018/05/29 Javascript
[02:45]DOTA2英雄基础教程 伐木机
2013/12/23 DOTA
[58:37]Serenity vs Fnatic 2018国际邀请赛淘汰赛BO1 8.21
2018/08/22 DOTA
[43:43]完美世界DOTA2联赛PWL S2 LBZS vs Forest 第三场 11.29
2020/12/02 DOTA
python操作数据库之sqlite3打开数据库、删除、修改示例
2014/03/13 Python
Python的多维空数组赋值方法
2018/04/13 Python
关于python写入文件自动换行的问题
2018/06/23 Python
Python爬虫爬取新浪微博内容示例【基于代理IP】
2018/08/03 Python
在python中bool函数的取值方法
2018/11/01 Python
django session完成状态保持的方法
2018/11/27 Python
python应用Axes3D绘图(批量梯度下降算法)
2020/03/25 Python
keras 如何保存最佳的训练模型
2020/05/25 Python
浅谈CSS3动画的回调处理
2016/07/21 HTML / CSS
美国时尚在线:Showpo
2017/09/08 全球购物
毕业自我鉴定
2013/11/05 职场文书
安全责任书范文
2014/03/12 职场文书
学前班评语大全
2014/05/04 职场文书
师范学院毕业生求职信
2014/06/24 职场文书
商务英语专业求职信
2014/06/26 职场文书
会计求职简历自我评价
2015/03/10 职场文书
高一作文之暖冬
2019/11/09 职场文书
解析MySQL索引的作用
2022/03/03 MySQL
Redis 的查询很快的原因解析及Redis 如何保证查询的高效
2022/03/16 Redis
ubuntu如何搭建vsftpd服务器
2022/12/24 Servers