如何在运行时编译函数?

时间:2015-09-06 23:09:22

标签: python

Python 3.x中是否有一种方法可以使用标准库在运行时编译函数并通过函数对象使用它?

我尝试了以下内容:

class A:    
    def meth1(self, par1):
        print("in A.meth1: par1 =", par1)

a = A()
s = '''def meth1(self, par1):
    print("in recompiled A.meth1: par1 = ", par1)'''
a.meth1.__func__.__code__ = compile( s, __file__, "exec")
a.meth1("via meth1")

但这会产生错误:

  

TypeError:<module>()取0个位置参数,但给出2个

compile()的文档中,它写了用它编译的代码可以使用eval()exec()运行。有没有办法编译一个函数并通过函数对象调用它而没有eval()和exec()?

3 个答案:

答案 0 :(得分:2)

您可能必须通过exec()eval()运行它才执行函数定义。您可以将它传递给一个单独的环境,您必须自己从中提取函数(正如用户HelloWorld正确地说,Python不能&#34;猜测&#34;您的意思是哪个函数)。

回到你的例子,在这里我首先创建一个空的环境environment,然后将编译的代码和字典传递给exec,以便评估定义。使用types库中的MethodType类,必须将函数转换为绑定方法,将类或实例作为第二个参数。然后,您可以将绑定方法附加到原始实例。

import types

class A:    
    def meth1(self, par1):
        print("in A.meth1: par1 =", par1)

a = A()
s = '''def meth1(self, par1):
    print("in recompiled A.meth1: par1 = ", par1)'''

code = compile(s, __file__, "exec")

environment = {}
exec(code, environment)
a.meth1 = types.MethodType(environment["meth1"], A)

a.meth1("via meth1")

答案 1 :(得分:1)

jojonas给出了一个很好的答案,这篇文章更多的是评论而不是答案。

您不能简单地编译字符串并从类中替换代码对象。调用compile后得到的是代码对象。例如。看看下面的代码。

obj = '''
def meth1(self, par1):
    print("in recompiled A.meth1: par1 = ", par1)

def meth2(self, par1):
        print("in recompiled A.meth2: par1 = ", par1)
'''
a.meth1.__func__.__code__ = compile(obj, __file__, "exec") # What should happen here?

从这个例子中可以看出,我们编译了一个不能简单地附加到类的整个范围。你要做的是从代码对象中提取meth1函数并改为使用它。

你应该看看下面关于代码对象的好文章,它会为你提供一些很好的见解。

http://late.am/post/2012/03/26/exploring-python-code-objects.html

答案 2 :(得分:0)

对于有价值的东西,我最近创建了一个@compile_fun好吃的东西,它大大简化了在函数上应用compile的过程。您的示例写道:

class A:
    @compile_fun
    def meth1(self, par1):
        print("in A.meth1: par1 =", par1)

您会看到现在无法使用IDE调试到meth1中。请注意,这不会提高运行时性能,也不会保护代码免受逆向工程的影响,但是如果您不希望用户在调试时看到函数的内部结构,这可能会很方便。请注意,明显的缺点是它们将无法帮助您调试lib,因此请谨慎使用!

有关详细信息,请参见makefun documentation