Python骚操作:动态定义函数

简介: Python骚操作:动态定义函数

在 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())

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


相关文章
|
21天前
|
算法 Python 容器
Python编程 - 不调用相关choose库函数,“众数“挑选器、随机挑选器 的源码编程实现
Python编程 - 不调用相关choose库函数,“众数“挑选器、随机挑选器 的源码编程实现
44 0
|
21天前
|
存储 程序员 Shell
Python 进阶指南(编程轻松进阶):十、编写高效函数
Python 进阶指南(编程轻松进阶):十、编写高效函数
46 0
|
21天前
|
存储 Shell C++
零基础学会python编程——输入 / 输出函数与变量
零基础学会python编程——输入 / 输出函数与变量
99 0
|
Python
Python编程中类的属性获取、设置、判断是否存在等,实战hasattr和getattr函数的应用案例!
Python编程中类的属性获取、设置、判断是否存在等,实战hasattr和getattr函数的应用案例!
149 0
|
编解码 安全 Python
【Python编程】八、Python函数详解
【Python编程】八、Python函数详解
133 0
【Python编程】八、Python函数详解
|
索引 Python
Python 编程 | 连载 23 - 常用函数与高阶函数
Python 编程 | 连载 23 - 常用函数与高阶函数
Python 编程 | 连载 23 - 常用函数与高阶函数
Python 编程 | 连载 14 - Python 的函数
Python 编程 | 连载 14 - Python 的函数
Python 编程 | 连载 14 - Python 的函数
|
算法 编译器 Python
Python编程基础:实验6——函数的递归
有关Python函数递归的一些题目,非常经典,开箱即用。
290 1
Python编程基础:实验6——函数的递归
|
编译器 Python Windows
Python编程基础:函数的使用
在Python学习中函数的作用不言而喻,熟练的使用函数能让我们的代码更加的简洁,增加可读性。
100 0
Python编程基础:函数的使用
|
Python
Python编程 print输出函数
本章将会讲解Python编程中的 print()输出函数
107 0
Python编程 print输出函数