我有一个类'Listener',它将回调连接到D-Bus信号。回调和信号名称由另一个类“客户端”提供。如果客户端提供的回调被传递给connect_to_signal(在dbus.Interface上)作为接收信号时使用的回调,则一切都按预期工作,即在收到连接信号时调用类Client中的回调方法。
但是,如果我想在继续调用Clients回调之前“拦截”信号并评估有效负载,我想我可以使用lambda表达式并将其传递给connect_to_signal方法,如下例所示:
import dbus
from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True)
from gi.repository import GObject
class Client(object):
def __init__(self):
bus = dbus.SystemBus()
obj = bus.get_object("org.freedesktop.UDisks", "/org/freedesktop/UDisks")
interface = dbus.Interface(obj, "org.freedesktop.UDisks")
listener = Listener()
signals_and_callbacks = {"DeviceAdded": self.device_added,
"DeviceChanged": self.device_changed}
listener.listen_to_signals(interface, signals_and_callbacks)
def device_added(self, payload):
print "in device_added ", payload
def device_changed(self, payload):
print "in device_changed ", payload
class Listener(object):
def listen_to_signals(self, interface, signals_and_callbacks):
for signal, callback in signals_and_callbacks.items():
cb = lambda x: self.signal_cb(x, callback)
interface.connect_to_signal(signal, cb)
def signal_cb(self, opath, subscriber_cb):
print subscriber_cb
subscriber_cb(opath)
if __name__ == "__main__":
client = Client()
mainloop = GObject.MainLoop()
mainloop.run()
但这不符合预期。信号连接,在这种情况下,代码对“DeviceAdded”和“DeviceChanged”都做出反应,但只调用最后一次回调。如果我只连接一个信号,行为就像预期的那样,但是一旦连接多个信号,将lambda表达式作为回调传递,两个信号就会触发对 last 回调补充。
有谁知道这里发生了什么?
答案 0 :(得分:1)
基本问题是Python的范围规则以及如何设置回调 此示例说明了您的问题(和解决方案):
def test1():
print("test1")
def test2():
print("test2")
def caller(name, fn):
print("calling function with name: {}".format(name))
fn()
class Driver(object):
def __init__(self):
self.signals = []
def connect_to_signal(self, name, what_to_call):
self.signals.append((name, what_to_call))
def run(self):
for name, signal in self.signals:
signal(1)
def main():
signals = {'test1':test1, 'test2':test2}
d = Driver()
for signal, callback in signals.items():
cb = lambda x: caller(signal, callback)
#cb = lambda x,s=signal,c=callback: caller(s, c) # TRY THIS INSTEAD!
d.connect_to_signal(signal, cb)
d.run()
if __name__ == '__main__':
main()
如果按原样运行此功能,您将获得以下内容:
calling function with name: test2
test2
calling function with name: test2
test2
如果您注释掉从cb = lambda x开始的行,并取消注释以下行,您现在可以得到所需的行:
calling function with name: test1
test1
calling function with name: test2
test2
原因是你需要capture
lambda表达式中的变量,或者它们的值只是它们在循环结束时的值。