2

什么是创建类的新成员函数的最佳方法,其中函数名称包含为字符串?此外,这个新函数仅作为另一个对象(帮助类)的传递,该对象具有相同的函数名称但具有可变参数。我使用 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
4

3 回答 3

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

综上所述,您可能需要重新考虑您的架构。它很紧张。

于 2013-10-23T02:52:35.573 回答
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'    
于 2013-10-23T02:51:54.353 回答
2

您正在寻找setattr/ getattr

for func_name in fnNames:
    setattr(employee, func_name, (lambda self, *args:getattr(self.compensation, func_name)(*args)))

这仍然有一个问题,因为您需要关闭func_namelambda 函数。虽然您可以使用另一个 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))
于 2013-10-23T02:52:12.253 回答