一个类如何生成一个回调函数,它根据类属性而改变?

Posted

技术标签:

【中文标题】一个类如何生成一个回调函数,它根据类属性而改变?【英文标题】:How can a class generate a callback function, that changes according to a class attribute? 【发布时间】:2018-10-10 01:24:13 【问题描述】:

我有这种情况:

module1.py:

class AudioEngine:
    def __init__(self):
        self.liverecording = False

    def getaudiocallback(self):

        def audiocallback(in_data, frame_count, time_info, status):  # these 4 parameters are requested by pyaudio
            data = None      # normally here we process the audio data
            if self.liverecording:
                print("Recording...")
            return data

        return audiocallback

main.py:

import module1

a = module1.AudioEngine()
f = a.getaudiocallback()

f(0, 0, 0, 0)

a.liverecording = True

f(0, 0, 0, 0)  # prints "Recording...", which is the expected behaviour, but why does it work?

问题:如何让回调函数audiocallback(...)对应a.liverecording的新值变化?如果它开箱即用,为什么会这样?

更具体地说,f,一旦使用f = a.getaudiocallback() 创建,是否在其代码中保留指向a.liverecording 的指针(因此如果修改了后者,将考虑到这一点) , 或 在创建 f 时的值的副本 a.liverecording(即False)?

【问题讨论】:

第二个 sn-p 不起作用的原因是因为您分配给 a.recording 而不是 a.liverecording。第一个可能和pyAudio有关。 就类和闭包而言,您所做的完全正确。正如@Aran-Fey 指出的那样,如果您使用正确的变量名,它实际上在您的非 pyaudio 示例中工作得很好。所以实际的问题(假设它不是一个类似的错字)可能 pyaudio 特定的。例如,你甚至知道你的回调被调用了吗? (如果添加else: print('not recording')会怎样?) @Basj 你是在问f 是如何最终成为捕获self 的闭包,还是需要一个关于闭包是什么以及它们如何工作的完整教程? this 回答你的问题了吗? 我看不出有什么不同。 n 是你的selfx 是你的in_data, frame_count, time_info, status 【参考方案1】:

如果您了解闭包,这里唯一的技巧是您在闭包中捕获的局部变量是getaudiocallback 中的self 参数。

在该方法中,self 当然是AudioEngine 实例a。因此,您捕获的变量的值就是同一个实例。

事实上,Python 可以让您在运行时反射几乎所有内容,因此您可以直接看到这一点:

>>> f = a.getaudiocallback()
>>> f
<function __main__.AudioEngine.getaudiocallback.<locals>.audiocallback(in_data, frame_count, time_info, status)>
>>> f.__closure__[0].cell_contents
<__main__.AudioEngine at 0x11772b3c8>
>>> f.__closure__[0].cell_contents is a
True

如果getaudiocallback 仍然存在,并且将self 反弹到某个其他值,则f.__closure__[0] 将更新为指向self 的新值。既然它已经退出了,那就永远不会发生;单元格将始终指向调用该方法时位于 a 中的实例。

但如果该实例后来发生变异,例如当您编写 a.liverecording = True 时,您当然可以看到。

【讨论】:

以上是关于一个类如何生成一个回调函数,它根据类属性而改变?的主要内容,如果未能解决你的问题,请参考以下文章

Scrapy 框架,爬虫文件相关

我们如何根据元类中 init 传递的属性来改变属性

NS3 Config类API说明

异步回调函数-创建进程的三种方式

Delphi-IDE:如何改变类完成的工作方式?

类属性评估和生成器