self 必须是 位置 参数,而不是关键字参数:
def wrapper(self, *args, **kwargs):
# ^^^^ You can't use "self=None" here.
slot_func(self, *args, **kwargs)
如果您需要区分函数和方法,请改为实现descriptor。
但是,如果您尝试连接信号,则需要对每个实例上的绑定方法这样做。您最好在实例创建时连接您的信号:
class manager(object):
def __init__(self):
update.connect(self.update)
def update(self):
print("I'm updating, yay!!!!")
当manager.__init__被调用时,你有一个新的实例,然后你可以创建一个self.update绑定方法来接收信号。
您仍然可以为此使用装饰器,但您最多可以在类级别注册哪些函数可以充当信号处理程序;您必须在实例创建时枚举类上的所有函数,然后绑定所有这些信号:
class connector(object):
def __init__(self, signal):
self.signal = signal
def __call__(self, slot_func):
slot_func._signal_handler = self.signal
return slot_func
还有一个单独的类装饰器来包装class.__init__ 方法:
from inspect import getmembers, isfunction
def connectsignals(cls):
signal_handlers = getmembers(
cls, lambda m: isfunction(m) and hasattr(m, '_signal_handler'))
init = getattr(cls, '__init__', lambda self: None)
def wrapper(self, *args, **kwargs):
init(self, *args, **kwargs)
for name, handler in signal_handlers:
handler._signal_handler.connect(handler.__get__(self))
cls.__init__ = wrapper
return cls
装饰类以及信号处理程序:
@connectsignals
class manager(object):
@connector(update)
def update(self):
print("I'm updating, yay!!!!")
装饰器会在每次创建新实例时连接所有处理程序:
>>> class Signal(object):
... def connect(self, handler):
... print('connecting {!r}'.format(handler))
...
>>> update = Signal()
>>> @connectsignals
... class manager(object):
... @connector(update)
... def update(self):
... print("I'm updating, yay!!!!")
...
>>> manager()
connecting <bound method manager.update of <__main__.manager object at 0x105439ac8>>
<__main__.manager object at 0x105439ac8>
您可能想检查signalslot 项目是否使用弱引用来跟踪信号处理程序,因为您可能会遇到对您创建的任何实例的循环引用问题(其中manager 实例保持活动状态,因为信号仍在引用该实例的绑定方法),或者您的信号处理程序被清理得太早,因为您的绑定方法存储在弱引用中,因此不会有任何 other 引用让他们活着。
查看signalslot source code,我看到该项目的当前迭代使用硬引用,因此除非您明确这样做,否则您的manager 实例永远不会被清除。仅出于这个原因,我会避免使用方法作为信号处理程序。如果您想改用弱引用,请查看using python WeakSet to enable a callback functionality。