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使用正则搜索字符串或文件中的浮点数代码实例
Jul 11 Python
一个基于flask的web应用诞生 使用模板引擎和表单插件(2)
Apr 11 Python
Python 获得13位unix时间戳的方法
Oct 20 Python
Python for循环中的陷阱详解
Jul 13 Python
详解numpy的argmax的具体使用
May 27 Python
python  logging日志打印过程解析
Oct 22 Python
python将时分秒转换成秒的实例
Dec 07 Python
详解Python中字符串前“b”,“r”,“u”,“f”的作用
Dec 18 Python
基于Pycharm加载多个项目过程图解
Jan 19 Python
python实现批量修改文件名
Mar 23 Python
Python中Selenium库使用教程详解
Jul 23 Python
python/golang实现循环链表的示例代码
Sep 14 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计算当前程序执行时间示例
2014/04/24 PHP
php简单解析mysqli查询结果的方法(2种方法)
2016/06/29 PHP
什么是PHP7中的孤儿进程与僵尸进程
2019/04/14 PHP
Cookie 注入是怎样产生的
2009/04/08 Javascript
高亮显示web页表格行的javascript代码
2010/11/19 Javascript
Jquery为a标签的href赋值实现代码
2013/05/03 Javascript
IE下JS读取xml文件示例代码
2013/08/05 Javascript
js charAt的使用示例
2014/02/18 Javascript
jQery使网页在显示器上居中显示适用于任何分辨率
2014/06/09 Javascript
实现图片预加载的三大方法及优缺点分析
2014/11/19 Javascript
Bootstrap项目实战之首页内容介绍(全)
2016/04/25 Javascript
详解JavaScript对象类型
2016/06/16 Javascript
Bootstrap表单布局样式源代码
2016/07/04 Javascript
jQuery实现验证码功能
2017/03/17 Javascript
vuejs绑定class和style样式
2017/04/11 Javascript
angularjs select 赋值 ng-options配置方法
2018/02/28 Javascript
angularjs 缓存的使用详解
2018/03/19 Javascript
js canvas实现红包照片效果
2018/08/21 Javascript
nodejs 使用nodejs-websocket模块实现点对点实时通讯
2018/11/28 NodeJs
nodejs二进制与Buffer的介绍与使用
2019/07/11 NodeJs
解决layui中onchange失效以及form动态渲染失效的问题
2019/09/27 Javascript
[01:49]一目了然!DOTA2DotA快捷操作对比第二弹
2014/05/16 DOTA
wxPython窗口的继承机制实例分析
2014/09/28 Python
学习python之编写简单简单连接数据库并执行查询操作
2016/02/27 Python
Python中字典(dict)合并的四种方法总结
2017/08/10 Python
使用Python paramiko模块利用多线程实现ssh并发执行操作
2019/12/05 Python
python nohup 实现远程运行不宕机操作
2020/04/16 Python
Tensorflow中的降维函数tf.reduce_*使用总结
2020/04/20 Python
HTML5头部标签的一些常用信息小结
2016/10/23 HTML / CSS
如何利用find命令查找文件
2015/02/07 面试题
优秀毕业大学生推荐信
2013/11/13 职场文书
领导干部保密承诺书
2014/08/30 职场文书
2015届大学生就业推荐表自我评价
2014/09/27 职场文书
Oracle更换为MySQL遇到的问题及解决
2021/05/21 Oracle
制作能在nginx和IIS中使用的ssl证书
2021/06/21 Servers
动画电影《龙珠超 超级英雄》延期上映
2022/03/20 日漫