我需要在运行时为方法生成代码.能够运行任意代码并拥有文档字符串非常重要.
我想出了一个解决方案相结合exec
,并setattr
,这里是一个虚拟的例子:
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()
哪个应该打印:
in dynamo 0
in dynamo 1
函数文档字符串和名称是可变属性.你可以在内部函数中做任何你想做的事情,或者甚至有makedynamo()选择的内部函数的多个版本.无需使用字符串构建任何代码.
这是解释器的一个片段:
>>> 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
(我知道这不是很好的代码,但它得到了重点).至于设置文档字符串,我知道这是可能的,但我必须在文档中查找它.
编辑:您可以设置文档字符串dynamo.__doc__
,因此您可以在循环体中执行以下操作:
dynamo.__doc__ = "Adds %s to the weight" % i
另一个编辑:在@eliben和@bobince的帮助下,应该解决闭包问题.