我该如何编写一个简单的回调函数?

26
我有这个示例代码,试图演示如何使用回调函数:
def callback(a, b):
    print('Sum = {0}'.format(a+b))

def main(callback=None):
    print('Add any two digits.')
    if callback != None:
        callback

main(callback(1, 2))

我得到了这个结果:
Sum = 3
Add any two digits.

看起来回调函数在main中的逻辑之前执行。为什么?如何才能使回调函数在main中使用之前不被调用?


1
与单例对象(如None)的比较应始终使用is或is not,而不是等于运算符。因此,在您的情况下,if callback is not None 将是正确的选择。 - pfabri
7个回答

62

在这段代码中

if callback != None:
    callback

callback单独使用没有任何作用;它可接受参数-def callback(a, b):

你先执行callback(1, 2),这将调用该函数,从而打印Sum = 3,然后将callback函数的结果作为参数调用main()函数,打印第二行。

由于callback没有返回明确的值,所以作为None返回。

因此,您的代码等效于

callback(1, 2)
main()

解决方案

您可以尝试不要在最开始调用该函数,而是只传递其句柄。

def callback(n):
    print("Sum = {}".format(n))

def main(a, b, _callback = None):
    print("adding {} + {}".format(a, b))
    if _callback:
        _callback(a+b)

main(1, 2, callback)

1
在回调之前传递两个参数让解释器为您完成一些工作是一个好主意! - erip
1
@erip 你是什么意思?喜欢你的回答吗? - OneCricketeer
1
我的意思是你的想法很好。 :) 强制用户在回调之前传递参数可以确保它们存在,以免调用“main”时出现错误。 - erip
@cricket_007,回调方法是将可调用对象传递给函数或类的一种方式,以便稍后调用它,这个说法正确吗? - garej
if _callback的意思是什么? 当我们像main(1, 2, callback)这样传递函数时,_callback将返回true,但我不明白if语句如何评估为true? - nad87563
1
如果函数句柄已经被定义(不是None) @nad87563 - OneCricketeer

10

这是您想要做的:

def callback(a, b):
    print('Sum = {0}'.format(a+b))

def main(a,b,f=None):
    print('Add any two digits.')
    if f is not None:
        f(a,b)

main(1, 2, callback)

5
问题在于您在将回调函数作为可调用对象传递之前对其进行了评估。解决这个问题的一种灵活方法是这样的:
def callback1(a, b):
    print('Sum = {0}'.format(a+b))

def callback2(a):
    print('Square = {0}'.format(a**2))

def callback3():
    print('Hello, world!')

def main(callback=None, cargs=()):
    print('Calling callback.')
    if callback is not None:
        callback(*cargs)

main(callback1, cargs=(1, 2))
main(callback2, cargs=(2,))
main(callback3)

可选地,您可能希望包含一种支持关键字参数的方法。


4

如评论中所述,当回调函数以开放和关闭括号结尾时,它将被调用;因此,当您传递它时,它将被调用。

您可能希望使用lambda并传入值。

#!/usr/bin/env python3

def main(callback=None, x=None, y=None):
    print('Add any two digits.')
    if callback != None and x != None and y != None:
        print("Result of callback is {0}".format(callback(x,y)))
    else:
        print("Missing values...")

if __name__ == "__main__":
    main(lambda x, y: x+y, 1, 2)

2

您的代码将按如下方式执行:

main(callback(1, 2))

callback函数被调用时使用(1, 2)作为参数,并返回None(如果没有返回语句,您的函数会打印Sum = 3并返回None

main函数被调用时使用None作为参数(因此callback != None将始终为False


1
这是一个旧帖子,但以下内容或许可以对编写和使用回调函数进行进一步解释,特别是如果你想知道回调函数的参数来自何处以及是否能够访问其返回值(如果无法从接受回调函数的函数中获得)。
以下代码定义了一个名为CallBack的类,该类具有两个回调方法(函数)my_callback_summy_callback_multiply。回调方法被注入到方法foo中。
# understanding callback

class CallBack:

    @classmethod
    def my_callback_sum(cls, c_value1, c_value2):
        value = c_value1 + c_value2
        print(f'in my_callback_sum --> {c_value1} + {c_value2} = {value}')
        cls.operator = '+'
        return cls.operator, value

    @classmethod
    def my_callback_multiply(cls, c_value1, c_value2):
        value = c_value1 * c_value2
        print(f'in my_callback_multiply --> {c_value1} * {c_value2} = {value}')
        cls.operator = '*'
        return cls.operator, value

    @staticmethod
    def foo(foo_value, callback):
        _, value = callback(10, foo_value)
        # note foo only returns the value not the operator from callback!
        return value


if __name__ == '__main__':
    cb = CallBack()

    value = cb.foo(20, cb.my_callback_sum)
    print(f'in main --> {value} and the operator is {cb.operator}')

    value = cb.foo(20, cb.my_callback_multiply)
    print(f'in main --> {value} and the operator is {cb.operator}')

结果:
in my_callback_sum --> 10 + 20 = 30
in main --> 30 and the operator is +
in my_callback_multiply --> 10 * 20 = 200 
in main --> 200 and the operator is *

如您所见,回调函数c_value2的一个值来自于foo中的参数foo_value,并在main中给出值20,而c_value1则从foo内部获取,此时为值10(如果foo是第三方导入模块(如pyaudio)的某种方法,则可能不太明显)。
回调函数的返回值可以通过将其添加到CallBack类的命名空间中来检索,在这种情况下为cls.operator

这似乎不是回调函数,因为它没有“回调”在类外定义的函数。对我来说,这是一个按引用传递的函数...这是一种很好的抽象技术,但在我看来并不是严格意义上的回调函数。 - Scott Lundberg

0

您可以使用匿名函数

def callback(a, b):
    print('Sum = {0}'.format(a+b))

def main(callback=None):
    print('Add any two digits.')
    if callback is not None:
        callback()

tmp_func = lambda: main(lambda: callback(2,3))
tmp_func()

#OR

tmp_func = lambda x,y: main(lambda: callback(x,y))
tmp_func(2,4)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接