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 18 Python
Python新手在作用域方面经常容易碰到的问题
Apr 03 Python
python实现的用于搜索文件并进行内容替换的类实例
Jun 28 Python
如何使用python爬取csdn博客访问量
Feb 14 Python
Python多线程编程之多线程加锁操作示例
Sep 06 Python
Python变量类型知识点总结
Feb 18 Python
python实现抽奖小程序
Apr 15 Python
Python3简单实现串口通信的方法
Jun 12 Python
Python爬虫学习之获取指定网页源码
Jul 30 Python
Python一行代码解决矩阵旋转的问题
Nov 30 Python
Python tensorflow实现mnist手写数字识别示例【非卷积与卷积实现】
Dec 19 Python
Python标准库itertools的使用方法
Jan 17 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中调用JAVA
2006/10/09 PHP
php Smarty date_format [格式化时间日期]
2010/03/15 PHP
php单例模式实现方法分析
2015/03/14 PHP
PHP 实现文件压缩解压操作的方法
2019/06/14 PHP
PHP开发api接口安全验证操作实例详解
2020/03/26 PHP
基于jQuery的弹出框插件
2012/03/18 Javascript
jQuery中:selected选择器用法实例
2015/01/04 Javascript
JavaScript实现仿网易通行证表单验证
2015/05/25 Javascript
JS中字符串trim()使用示例
2015/05/26 Javascript
基于vue,vue-router, vuex及addRoutes进行权限控制问题
2018/05/02 Javascript
JavaScript中 ES6变量的结构赋值
2018/07/10 Javascript
JavaScript函数的特性与应用实践深入详解
2018/12/30 Javascript
Vue中的情侣属性$dispatch和$broadcast详解
2019/03/07 Javascript
微信小程序使用websocket通讯的demo,含前后端代码,亲测可用
2019/05/22 Javascript
[51:15]2014 DOTA2国际邀请赛中国区预选赛 Orenda VS LGD-GAMING
2014/05/22 DOTA
[00:30]塑造者的传承礼包-戴泽“暗影之焰”套装展示视频
2014/04/04 DOTA
win10系统中安装scrapy-1.1
2016/07/03 Python
利用python写个下载teahour音频的小脚本
2017/05/08 Python
python smtplib模块自动收发邮件功能(二)
2018/05/22 Python
Python Flask框架模板操作实例分析
2019/05/03 Python
tensorflow模型继续训练 fineturn实例
2020/01/21 Python
使用Python发现隐藏的wifi
2020/03/04 Python
jupyter notebook中新建cell的方法与快捷键操作
2020/04/22 Python
英国骑行、跑步、游泳、铁人三项运动装备专卖店:Wiggle
2016/08/23 全球购物
美国在线家居装饰店:Belle&June
2018/10/24 全球购物
俄罗斯运动、健康和美容产品在线商店:Lactomin.ru
2020/07/23 全球购物
常用UNIX 命令(Linux的常用命令)
2013/07/10 面试题
美德好少年事迹材料
2014/01/19 职场文书
元宵晚会主持词
2014/03/25 职场文书
纪念9.18事变演讲稿
2014/09/14 职场文书
《微笑着面对生活》优秀演讲稿范文
2014/09/23 职场文书
光荣之路观后感
2015/06/12 职场文书
政审证明材料
2015/06/19 职场文书
圣诞晚会主持词
2015/07/01 职场文书
golang json数组拼接的实例
2021/04/28 Golang
MySQL学习之基础操作总结
2022/03/19 MySQL