是否可以在python中以编程方式创建对象方法?
由于使用命令行解析器的现有结构,我需要任意数量的方法 (N(,其中 (N( 在运行时建立。
def activatetool_>N<():
print 'activating tool number: >N<'
我设法接近:
class TestClass:
def __init__(self, toolcount):
for i in range(toolcount):
exec('def activatetool_{}(): print 'activating tool {}''.format(i,i)) in globals()
但是,这定义了全局函数,而不是类方法。通过设计我正在使用的现有代码,我需要能够以以下形式调用它们:
obj=TestClass(5)
obj.activatetool3()
obj.activatetool1()
澄清:由于我正在使用的现有解析器的结构,重构为obj.activatetool(N)
形式的解决方案是不可行的。
python方法只是类的一个属性,它恰好是一个接受类的实例作为其第一个参数的函数。因此,您只需使用 setattr
将新方法绑定到现有类。
从您的示例中,您可以创建一个函数来添加工具:
def addTool(cls, n):
def tool(self):
print ('activating tool number >{}<'.format(n))
setattr(cls, "activatetool{}".format(n), tool)
然后,您可以创建一个类,它的实例,添加一个工具并成功使用该工具:
class TestClass:
pass
t = TestClass()
addTool(TestClass, 3)
t.activatetool3()
您可以按预期获得:
activating tool number >3<
Python 的神奇之处在于,由于动态方法是类的一个属性,因此类的所有实例都可以访问它,即使它们是在添加方法之前创建的。
N
作为参数传递给activatetool
.
class TestClass:
def activatetool(self, N):
print "activating tool number: {}".format(N)
obv=TestClass()
obv.activatetool(3)
obv.activatetool(1)
结果:
activating tool number: 3
activating tool number: 1
如果您完全死心塌地地将数字保留在括号之外,您可以通过覆盖__getattr__
来获得大致您想要的行为:
import re
class TestClass:
def __getattr__(self, name):
m = re.match("activatetool(d*)$", name)
if m:
N = int(m.group(1))
def activatetoolN():
print("Activating tool number: {}".format(N))
return activatetoolN
else:
raise AttributeError
obv=TestClass()
obv.activatetool3()
obv.activatetool1()
结果:
Activating tool number: 3
Activating tool number: 1
但是,obv.activatetool3 的类型为 function
,而普通实例方法的类型为 instancemethod
。大多数情况下,你无法分辨出区别,但类中异常严格的用户可能会注意到这种差异。
还会有小到中等的性能损失,因为每次访问activatetoolN
时都会从头开始创建obv.activatetool<N>
。