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进行稳定可靠的文件操作详解
Dec 31 Python
介绍Python的Django框架中的QuerySets
Apr 20 Python
Django URL传递参数的方法总结
Aug 28 Python
老生常谈进程线程协程那些事儿
Jul 24 Python
在pycharm中python切换解释器失败的解决方法
Oct 29 Python
Python中dict和set的用法讲解
Mar 28 Python
Flask框架模板继承实现方法分析
Jul 31 Python
python+tkinter实现学生管理系统
Aug 20 Python
python scipy卷积运算的实现方法
Sep 16 Python
python中的itertools的使用详解
Jan 13 Python
在TensorFlow中屏蔽warning的方式
Feb 04 Python
linux系统下pip升级报错的解决方法
Jan 31 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
星际中的相关伤害
2020/03/04 星际争霸
php 将bmp图片转为jpg等其他任意格式的图片
2009/06/21 PHP
Php Image Resize图片大小调整的函数代码
2011/01/17 PHP
PHP数组 为文章加关键字连接 文章内容自动加链接
2011/12/29 PHP
PHP CURL模拟登录新浪微博抓取页面内容 基于EaglePHP框架开发
2012/01/16 PHP
将word转化为swf 如同百度文库般阅读实现思路及代码
2013/08/09 PHP
jQuery中的RadioButton,input,CheckBox取值赋值实现代码
2014/02/18 PHP
PHP关联数组实现根据元素值删除元素的方法
2015/06/26 PHP
php弹出提示框的是实例写法
2019/09/26 PHP
PHP之多条件混合筛选功能的实现方法
2019/10/09 PHP
如何用JavaScript定义一个类
2014/09/12 Javascript
JS+CSS实现可拖动的弹出提示框
2015/02/16 Javascript
jQuery实现鼠标划过修改样式的方法
2015/04/14 Javascript
详细分析JavaScript变量类型
2015/07/08 Javascript
jQuery实现仿百度帖吧头部固定导航效果
2015/08/07 Javascript
浅析JavaScript中命名空间namespace模式
2016/06/22 Javascript
浅谈jquery上下滑动的注意事项
2016/10/13 Javascript
浅谈js script标签中的预解析
2016/12/30 Javascript
JavaScript继承与多继承实例分析
2018/05/26 Javascript
Angular6 Filter实现页面搜索的示例代码
2018/12/02 Javascript
[01:07:46]完美世界DOTA2联赛循环赛 Magma vs IO BO2第二场 11.01
2020/11/02 DOTA
在Mac OS上部署Nginx和FastCGI以及Flask框架的教程
2015/05/02 Python
Python实现的字典排序操作示例【按键名key与键值value排序】
2018/12/21 Python
详解python3中用HTMLTestRunner.py报ImportError: No module named 'StringIO'如何解决
2019/08/27 Python
用Python进行websocket接口测试
2020/10/16 Python
python dir函数快速掌握用法技巧
2020/12/09 Python
使用纯HTML5编写一款网页上的时钟的代码分享
2015/11/16 HTML / CSS
Booking.com缤客中国:全球酒店在线预订网站
2020/05/03 全球购物
大学生入党思想汇报
2014/01/01 职场文书
工作会议欢迎词
2014/01/16 职场文书
经济信息系毕业生自荐信
2014/06/02 职场文书
庆六一开幕词
2015/01/29 职场文书
公司要求试用期员工提交“述职报告”,该怎么写?
2019/07/17 职场文书
SpringBoot整合Redis入门之缓存数据的方法
2021/11/17 Redis
POST提交数据常见的四种方式
2022/01/18 HTML / CSS
Python实现Hash算法
2022/03/18 Python