Python中的dynamic/运行时方法创build(代码生成)

我需要在运行时为方法生成代码。 能够运行任意代码并拥有文档string是非常重要的。

我想出了一个结合了execsetattr的解决scheme,下面是一个虚拟的例子:

 class Viking(object): def __init__(self): code = ''' def dynamo(self, arg): """ dynamo's a dynamic method! """ self.weight += 1 return arg * self.weight ''' self.weight = 50 d = {} exec code.strip() in d setattr(self.__class__, 'dynamo', d['dynamo']) if __name__ == "__main__": v = Viking() print v.dynamo(10) print v.dynamo(10) print v.dynamo.__doc__ 

是否有一个更好/更安全/更习惯的方式来达到相同的结果?

基于Theran的代码,但将其扩展到类的方法:

class Dynamo(object): pass def add_dynamo(cls,i): def innerdynamo(self): print "in dynamo %d" % i innerdynamo.__doc__ = "docstring for dynamo%d" % i innerdynamo.__name__ = "dynamo%d" % i setattr(cls,innerdynamo.__name__,innerdynamo) for i in range(2): add_dynamo(Dynamo, i) d=Dynamo() d.dynamo0() d.dynamo1()
class Dynamo(object): pass def add_dynamo(cls,i): def innerdynamo(self): print "in dynamo %d" % i innerdynamo.__doc__ = "docstring for dynamo%d" % i innerdynamo.__name__ = "dynamo%d" % i setattr(cls,innerdynamo.__name__,innerdynamo) for i in range(2): add_dynamo(Dynamo, i) d=Dynamo() d.dynamo0() d.dynamo1() 

应该打印哪个:

in dynamo 0 in dynamo 1
in dynamo 0 in dynamo 1 

函数文档和名称是可变的属性。 你可以在内部函数中做任何你想要的事情,或者甚至有makedynamo()select的内部函数的多个版本。 不需要从string中构build任何代码。

这里是解释器的一个片段:

 >>> def makedynamo(i): ... def innerdynamo(): ... print "in dynamo %d" % i ... innerdynamo.__doc__ = "docstring for dynamo%d" % i ... innerdynamo.__name__ = "dynamo%d" % i ... return innerdynamo >>> dynamo10 = makedynamo(10) >>> help(dynamo10) Help on function dynamo10 in module __main__: dynamo10() docstring for dynamo10 

Python会让你在一个函数中声明一个函数,所以你不必做exec

 def __init__(self): def dynamo(self, arg): """ dynamo's a dynamic method! """ self.weight += 1 return arg * self.weight self.weight = 50 setattr(self.__class__, 'dynamo', dynamo) 

如果你想有几个版本的函数,你可以把所有这些放在一个循环中,并在setattr函数中改变你的名字:

 def __init__(self): for i in range(0,10): def dynamo(self, arg, i=i): """ dynamo's a dynamic method! """ self.weight += i return arg * self.weight setattr(self.__class__, 'dynamo_'+i, dynamo) self.weight = 50 

(我知道这不是很好的代码,但它可以得到重点)。 至于设置文档string,我知道这是可能的,但我不得不在文档中查找它。

编辑 :您可以通过dynamo.__doc__设置文档string,所以你可以在你的循环体中做这样的事情:

 dynamo.__doc__ = "Adds %s to the weight" % i 

另一个编辑 :在@eliben和@bobince的帮助下,应该解决closures问题。

对不起我英文不好。

我最近需要生成dynamic函数来绑定每个菜单项,以在wxPython上打开特定的框架。 这是我做的。

首先,我创build菜单项和框架之间的映射列表。

 menus = [(self.menuItemFile, FileFrame), (self.menuItemEdit, EditFrame)] 

映射中的第一项是菜单项,最后一项是要打开的框架。 接下来,我将每个菜单项的wx.EVT_MENU事件绑定到特定的框架。

 for menu in menus: f = genfunc(self, menu[1]) self.Bind(wx.EVT_MENU, f, menu[0]) 

genfunc函数是dynamic函数的构build器,下面是代码:

 def genfunc(parent, form): def OnClick(event): f = form(parent) f.Maximize() f.Show() return OnClick 
Interesting Posts