0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Python动态定义函数实现

454398 来源:Python猫 作者:Philip Trauner 2020-11-19 15:42 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

作者:Philip Trauner 译者:豌豆花下猫”

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

from types import FunctionType

foo_code = compile('def foo(): return "bar"', "", "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)

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"', "", "exec")

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

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

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

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

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

>>> print(foo_func())

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

结尾

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

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

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

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

译者简介: 豌豆花下猫,生于广东毕业于武大,现为苏漂程序员,有一些极客思维,也有一些人文情怀,有一些温度,还有一些态度。

编辑:hfy

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • python
    +关注

    关注

    59

    文章

    4892

    浏览量

    90414
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    使用LTspice定义电压源和电流源的分段线性函数

    分段线性(PWL)函数是一系列直线段,可用于在LTspice中创建电压或电流波形。PWL段通过时间/数值对进行定义,是瞬态仿真中用于描述电压或电流波形的众多方式之一。
    的头像 发表于 04-14 10:21 234次阅读
    使用LTspice<b class='flag-5'>定义</b>电压源和电流源的分段线性<b class='flag-5'>函数</b>

    使用Python/MyHDL创建自定义FPGA IP

    使用 Python/MyHDL 创建自定义 FPGA IP,与 Vivado 集成,并通过 PYNQ 进行控制——实现软件上的简单硬件设计。
    的头像 发表于 04-09 09:53 467次阅读
    使用<b class='flag-5'>Python</b>/MyHDL创建自<b class='flag-5'>定义</b>FPGA IP

    使用PYTHON进行的跨平台仿真

    快速物理光学软件VirtualLab Fusion以其“连接场求解器”方法而自豪,该方法将应用于不同组件上的专用电磁场求解器结合在一起,以实现整个系统的物理光学模拟。这种方法的逻辑扩展不仅是连接软件
    发表于 04-02 08:21

    [VirtualLab] 使用Python运行VirtualLab Fusion光学仿真

    Python编辑器的用户: 请安装保存在文件requirements.txt中的所有软件包。最常见的方法之一是pip安装: pip install -r requirements.txt 配置路径 在VirtualLab Fusion中定义光学系统 查看完整案例: 光
    发表于 03-31 09:39

    [VirtualLab] 使用Python进行跨平台参数扫描

    ** 准备Python **配置路径 ** **在VirtualLab Fusion中定义一个光学设置 ** **保存光学设置并导出参数到一个XML文件 ** **运行模拟 ** 参数扫描——改变单个参数
    发表于 03-31 09:36

    Python运行本地Web服务并实现远程访问

    本文介绍使用Python搭建本地Web服务并结合 ZeroNews 实现公网访问。
    的头像 发表于 02-06 11:39 441次阅读
    <b class='flag-5'>Python</b>运行本地Web服务并<b class='flag-5'>实现</b>远程访问

    keil定义fputc函数

    函数 fputc 是输出字符的底层函数,只需要实现这个函数,类似 printf、puts 等函数也可以正常使用了。 由于存在3种文件类型,这
    发表于 01-22 08:25

    函数指针与回调函数解读

    函数指针是指向函数的指针变量。通过函数指针C语言可以实现各种强大的功能与设计方法。而回调函数函数
    发表于 01-19 07:34

    matlab调用dll动态函数,死机问题,如何强行跳出?

    matlab调用dll动态库中的函数,例如图莫斯,发送数据时,经常会卡死,是否有办法限制时间,比如3秒,没有回应,就强行结束函数调用。执行后续逻辑。
    发表于 12-31 10:14

    在Termux环境下实现康威生命游戏

    表示细胞网格终端清屏+重绘实现动态效果初始化滑翔机初始位置 循环计算下一代细胞状态二、完整代码(可直接在Termux运行)python#!/usr/bin/env python
    发表于 12-21 18:36

    Python调用API教程

    随着互联网技术的发展,API(Application Programming Interface)的应用越来越广泛。API是指一系列预先定义好的接口,用于以标准化的形式、规范的方式、安全高效地完成
    的头像 发表于 11-03 09:15 1281次阅读

    riscv实现定义指令并用qemu运行

    人根据语法规则写了一个通用的python脚本来生产对应指令解析函数,这也是非常值得学习。qemu是通过指令集解析的,目前只需在decodetree中增加一条cube指令的实现即可。 在target
    发表于 10-31 07:37

    计算程序执行指令数的函数实现

    (来源:手把手教你设计cpu_RISC-V处理器),他们分别存储了指令计数器的高低32位 至此就大致能理解指令数计算函数实现原理,即通过csrr指令读minstreth和minstret寄存器得到执行操作前后的指令计数值,再取其差值即可得到该操作耗费的指令数。周期数计
    发表于 10-28 06:27

    CherryUSB怎样实现U盘动态加载?

    ,致使二者不能同时工作。使用CherryUSB怎样实现U盘动态挂载和卸载呢?即在不插USB线时,挂载文件系统,应用可正常使用文件系统,当插入USB线时,动态卸载文件系统并挂载U盘,当弹出U盘或插出
    发表于 10-14 07:31

    【M-K1HSE开发板免费体验】相关源码之阅读和分析1-使用XComponent + Vsync 实现定义动画

    介绍 XComponent 提供了应用在 native 侧调用 OpenGLES 图形接口的能力,本文主要介绍如何配合 Vsync 事件,完成自定义动画。在这种实现方式下,自定义动画的绘制不在 UI
    发表于 09-03 16:05