1. Python骚操作之动态定义函数

     更新时间:2019年03月26日 09:29:50   作者:豌豆花下猫   我要评论

    这篇文章主要介绍了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 都可以完成工作,但是查?#35789;导?#30340;源代码,则会揭示出关于数据类型的更多细节。

    >>> 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 ?#20540;?#20013;查找。

    内置的 globals() 方法会返回一个对当前模块的全局符号表(global symbol table)的引用 ,因此能被用来提供一个总是与当前表的状态相一致的?#20540;洹?#20256;入?#25105;?#20854;它的?#20540;?#20063;是可以的(FunctionType((lambda: bar).__code__, {"bar" : "baz"}, "foo")() == "baz")。

    3. name(可选)

    控制所返回的函数的__name__ 属性。只真正对 lambdas 有用(由于匿名性,它们通常没有名称),并且重命名函数。

    4. argdefs(可选)

    通过传入一个包含?#25105;?#31867;型的对象的元组,提供一个方式来供应默认参数值(def foo(bar="baz"))。(FunctionType((lambda bar: bar).__code__, {}, "foo", (10,))() == 10)。

    5. closure(可选)

    (如果需要在 CPython(PyPy,Jython,…)以外的其它 Python VM 中执行,可能不应?#20040;?#21450;,因为它?#29616;?#22320;依赖于实现细节)。

    一个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 的内部构件是一种深入学习这门语言的好方法。

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

    还是一如既往地:不要滥用语言 (好吧,一点点?#21442;?#22952;,对吧?)

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

    相关文章

    最新评论

    山东群英会开奖查询
      1. 中国足彩网彩 天津快乐10分网站 048期七乐彩专家预测 大乐透走势图带连线 一肖两码中特期期准 幸运农场水果开奖 体彩20选5号码走势图 两肖两码中特期期大公开 彩票合买规则 扑克王国语 多乐彩是什么 广西快乐十分包选 17094体彩号码 贵州11选5走势图更新 广东十一选五历史开奖号码查询结果