创建函数名包含为字符串的类的新成员函数的最佳方法是什么?此外,这个新函数仅仅是另一个对象(辅助类)的传递,它具有相同的函数名但具有可变参数。我使用lambda来实现这一点,但我不知道如何处理这个场景,我的传递包装器将不止一个语句(这是我的要求)
# This is a helper class
class Compensation:
def bonus(self):
return 10000
def salary(self):
# Do something
def stack(self):
# Do something
# This is a employer class
class employee:
def __init__(self):
self.compensation = Compensation()
# This is a wrapper that creates the function
def passThru(funcName):
fn = "employee."+funcName+"=" + "lambda self, *arg: self.compensation." + funcName +"(*arg)"
exec(fn)
fnNames = ["bonus", "salary", "stocks"]
for items in fnNames: passThru(items)
emp = employee()
emp.bonus() # returns 1000
答案 0 :(得分:5)
exec
的所有诡计让我很头疼;-)我不清楚你想做什么,但添加一个名字由字符串给出的新方法真的很容易。例如,
class employee:
pass
# Some multiline-function.
def whatever(self, a, b):
c = a + b
return c
e = employee()
# Make `whatever` an `employee` method with name "add".
setattr(employee, "add", whatever)
print e.add(2, 9)
每当你到达exec
时,你可能错过了一种直截了当的方式。
编辑:这里的一个奇怪之处是,如果有人试图显示e.add
,他们会得到一个声称其名称为whatever
的字符串。如果这困扰你,你可以添加,例如,
whatever.__name__ = "add"
这更接近你想要的吗?请注意,@gnibbler的建议大致相同,但更多的是电报:
class Compensation:
def bonus(self, a):
return 10000 + a
def salary(self):
return 20000
def stack(self, a=2, b=3):
return a+b
class employee:
def __init__(self):
self.comp = Compensation()
e = employee()
for name in "bonus", "salary", "stack":
def outer(name):
def f(self, *args, **kw):
return getattr(self.comp, name)(*args, **kw)
f.__name__ = name
return f
setattr(employee, name, outer(name))
print e.bonus(9)
print e.salary()
print e.stack(b="def", a="abc")
显示:
10009
20000
abcdef
所有这些,你可能想重新考虑你的架构。它很紧张。
答案 1 :(得分:2)
你想要setattr
。假设你有:
>>> inst = Foo(10)
>>> class Foo(object):
def __init__(self, x):
self.x = x
>>> inst = Foo(10)
>>> inst2 = Foo(50)
如果要向该类的所有实例添加方法,则在类上添加setattr
。这个函数最终将成为类中的一个未绑定方法,在每个实例中都会绑定,因此它将采用self
参数:
>>> setattr(inst.__class__, "twice_x", lambda self: self.x * 2)
>>> inst.twice_x()
20
>>> inst2.twice_x()
100
如果要将该函数仅添加到该类的一个实例中,则在实例本身上添加setattr
。这将是一个常规函数,它不会采用隐式self
参数:
>>> setattr(inst, "thrice_x", lambda: inst.x * 3)
>>> inst.thrice_x()
30
>>> inst2.thrice_x()
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
inst2.thrice_x()
AttributeError: 'Foo' object has no attribute 'thrice_x'
答案 2 :(得分:2)
您正在寻找setattr
/ getattr
。
for func_name in fnNames:
setattr(employee, func_name, (lambda self, *args:getattr(self.compensation, func_name)(*args)))
这仍然有问题,因为你需要lambda函数closed而不是func_name
。虽然您可以使用另一个lambda创建一个闭包,但我会将其拉出到另一个函数中以便于阅读
for func_name in fnNames:
def f(func_name): # close the lambda over "func_name"
return lambda self, *args:getattr(self.compensation, func_name)(*args)
setattr(employee, items, f(func_name))