有什么惯用的方法可以向 Python 中的对象添加方法吗?

Is there any idiomatic way to add methods to object in Python?

例如,我必须用一些基本的数学运算来制作计算器:

class Power_calc():
    def calculate(self, exp):
        self.srt = exp.split(" ")
        self.x = float(self.srt[0])
        self.y = float(self.srt[2])
        operand = self.srt[1]
        if operand == '+':
            return self.summ(self.x, self.y)
        elif operand == "-":
            return self.minus(self.x, self.y)

    def summ(self, a, b):
        return a + b

    def minus(self, a, b):
        return a - b

calc1 = Power_calc()
print calc1.calculate("3.2 + 6.0")

有什么方法可以像在 Javascript 中那样对字典中的所有计算器方法进行分组(下面的示例):

function powerCalculator() {
var methods = { //adding all methods here
    '+': function(a, b) {
        return a + b;
    },
    '-': function(a, b) {
        return a - b;
    }
};
this.calculate = function(expression) {
    var arr = expression.split(' '),
    a = +arr[0],
    b = +arr[2],
    operand = arr[1]
    return methods[operand](a, b);
}

是的,你可以做到。 Python 函数是 first-class 对象,因此您可以像在 JavaScript.

中一样将它们存储在字典中

如果您想在线定义函数,可以使用 lambdas:

methods = {
    '+': lambda a, b: a + b,
    # ...
}

或者仅引用外部函数:

def plus(a, b): return a + b

methods = {
    '+': plus,
    # ...
}

请注意,方法只是包装函数(存储 self 引用);您可以在字典中使用 self.summself.minus 来存储绑定方法:

class Power_calc():
    def calculate(self, exp):
        methods = {
            '+': self.summ,
            '-': self.minus,
        }

        self.srt = exp.split(" ")
        self.x = float(self.srt[0])
        self.y = float(self.srt[2])
        operand = self.srt[1]
        return methods[operand](self.x, self.y)

    def summ(self, a, b):
        return a + b

    def minus(self, a, b):
        return a - b

更简单,你可以使用这里的operator module进行预定义操作函数:

import operator

methods = {
    '+': operator.add
    # ...
}

你在 JS 中所做的不是添加方法,它只是创建一个从名称到函数的映射,然后你可以在 calculate 方法中显式使用它。您可以在 Python 中做完全相同的事情(并且使用更少的样板来启动):

class PowerCalculator(object):
    methods = {
        '+': (lambda a, b: a + b),
        '-': (lambda a, b: a - b)
    }
    def calculate(self, expression):
        arr = expression.split(' ')
        a = float(arr[0])
        b = float(arr[2])
        op = arr[1] # note that this is the operator, not the operand
        return self.methods[op](a, b)

这与您在 JS 中所做的完全不一样,但非常接近。在 JS 中,您正在创建一个范围,其中定义了 methods 变量,然后将原型的 calculate 方法定义为该范围内的闭包。虽然你 可以 在 Python 中这样做,但你不必这样做,因为你有 class 语句,它创建了一个专门用于定义方法和其他的范围class 中的属性,因此您可以正常定义 methods 并将其作为属性访问。


如果您真的想将 summminus 定义为方法而不是 lambda 的内联函数,您可以。但是,您可能希望它们是 @staticmethods — 毕竟,它们不会对 self.

做任何事情

如果你真的想让它们成为普通方法,你甚至可以这样做。但是你在 dict 中拥有的将是未绑定的方法,这意味着你必须显式传递 self 来调用它们。像这样:

class PowerCalculator(object):
    def summ(self, a, b):
        return a + b

    def minus(self, a, b):
        return a - b

    methods = {
        '+': summ,
        '-': minus
    }

    def calculate(self, expression):
        arr = expression.split(' ')
        a = float(arr[0])
        b = float(arr[2])
        op = arr[1] # note that this is the operator, not the operand
        return self.methods[op](self, a, b)

但是增加这种额外的复杂性确实没有任何好处。