Python Q&A #1: How to chain adding functions – add(1)(2)(3)

Yesterday a student asked about a question from codewars.com – A Chain adding function. Please check out the problem for the details.

The keypoint is, we need to return the sum for function calls like, add(1)(2)(3), which should be: 1 + 2 + 3 = 6.

In Python, a name followed by () indicates it’s a function call. For multiple parenthesis, we need to handle multiple function calls. Therefore, the left side calls should return a function to be invoked by the right side calls.

So my first thought is to return a function like follows:

function return function

Figure Q-1_1. Return function from a function.

However, the above code can only handle two consecutive calls. Not one, not three, only two. So it won’t work here.

To support multiple chain calls, we need to use class. There is a magic method in class, __call__, which could be used to enable class instances to behave like functions. For example, the following code defines a class Add. The instance of class Add, a, could be used as a function call.

magic method __call__

Figure Q-1_2. Define magic method __call__ for a class.

Using this trick, we could define a class based on INT to handle chain adding function calls like follows:

Chain adding functions

Figure Q-1_3. Define add class with magic method __call__ to support chain adding calls.

Note that add(1) will NOT invoke the magic method __call__ because class add is based on INT. So the instance itself is a number.


Python编程答疑#1:链接多个函数调用做加法


昨天有学生问一个Python编程练习题:A Chain adding function. 具体内容可以查看这个链接。这个问题的核心是需要处理多个连在一起的函数调用:add(1)(2)(3),需要返回结果是 1 + 2 + 3 = 6。

在Python语法中,一个变量名字后面跟着小括号代表函数调用,多个小括号连接在一起,表示前面的函数调用返回的结果也是一个函数。所以图例 Q-1_1里面的代码就返回了一个函数,这样它可以处理两个连在一起的加法调用。不过它也只能处理两个,不能多,不能少,这样就不符合要求。

如果要支持多个函数连续调用,我们就需要用到class,以及class里面的神奇函数,__call__。一个类定义了函数__call__之后,该类的实例可以当作函数来调用,图例 Q-1_2 里面的代码就展示了这种用法。

利用这种技巧,我们可以定义一个基类是INT的类,add,然后再定义函数 __call__,在里面返回当前实例加上 __call__的参数之和就可以了。因为add是INT类型,关键字self就是一个数字,所以可以把 self 和数字相加。图例 Q-1_3 展示了最后的解决方法。

注意:add(1) 不会触发函数__call__,因为add(1)只是创建了class add的一个实例。

下面是和学生实际答疑中的对话记录。

Chain Adding Function