[英]apply decorator class to class method
考慮以下裝飾者:
class connector(object):
def __init__(self, signal):
self.signal = signal
def __call__(self, slot_func):
def wrapper(*args, **kwargs):
slot_func(*args, **kwargs)
self.signal.connect(wrapper)
以下信號,以及我需要裝飾的方法類:
from signalslot import Signal
update = Signal()
class manager(object):
# SOME CODE CUT
@connector(update)
def update(self):
print("I'm updating, yay!!!!")
正如你所看到的,我需要傳遞裝飾器一些額外的參數,在這種情況下 - 我需要連接到的信號。 如何通過自我?
我問的原因,因為如果我嘗試將此裝飾器應用於方法而不是函數,它會失敗並出現以下錯誤:
TypeError:update()缺少1個必需的位置參數:'self'
更具體地說,如果我嘗試發出信號:
update.emit()
是的,我在該項目中使用“signalslot” 。
self
必須是位置參數,而不是關鍵字參數:
def wrapper(self, *args, **kwargs):
# ^^^^ You can't use "self=None" here.
slot_func(self, *args, **kwargs)
如果需要區分函數和方法,請改為實現描述符 。
但是,如果您嘗試連接信號,則需要對每個實例上的綁定方法執行此操作。 您最好在實例創建時連接信號:
class manager(object):
def __init__(self):
update.connect(self.update)
def update(self):
print("I'm updating, yay!!!!")
當調用manager.__init__
,你有一個新的實例,然后你就可以創建一個 self.update
bound方法來接收信號。
你仍然可以使用裝飾器,但是你可以在類級別注冊哪些函數可以充當信號處理程序; 您必須在實例創建時枚舉類中的所有函數,然后綁定所有這些信號:
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
實例保持活動狀態,因為信號仍然引用了一個邊界該實例的方法),或者您的信號處理程序過早清理,因為綁定的方法存儲在弱引用中,因此不會有任何其他引用來保持它們存活。
查看signalslot
源代碼 ,我看到項目的當前迭代使用了硬引用,因此除非您明確地執行此操作,否則永遠不會清除manager
實例。 僅僅因為這個原因,我會避免使用方法作為信號處理程序。 如果您想使用弱引用,請查看使用python WeakSet啟用回調功能 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.