I am wondering how I can setup a decorator in a class that can accept class variables. The example where I think this could be useful is in Pyside/PyQt where I need to block and unblock signals on widgets at the beginning and ending of functions.
Example:
class Window(QtGui.QMainWindow):
....
def updateList(self, *args):
self.list.blockSignals(False)
//do things on self.list
self.list.blockSignals(True)
Now, there is the potential of a lots of places on different widgets this could be done. Sure I can do this method of blocking and unblocking each item, but that's tedious. And I have to remember to unblock everything when I'm done.
Moving into another step, I can move the blocking into it's own function.
class Window(QtGui.QMainWindow):
....
def updateList(self, *args):
self.block([self.list])
//do things on self.list
self.block([self.list])
def block(self, items):
for item in items:
if item.signalsBlocked():
item.blockSignals(False)
else:
item.blockSignals(True)
Sweet! I can pepper that around my code and feels pretty useful. But I feel like there is some kind of final boss form I'm missing here to make it truely globally useful. Like some kind of decorator.
Using this answer here I can pass variables to my decorator and decorate my function! Decorators with parameters?
def block(items):
def dec(fn):
def wrapped(*args, **kwargs):
for item in items:
item.blockSignals(True)
fn(*args, **kwargs)
for item in items:
item.blockSignals(False)
return wrapped
return dec
class Window(QtGui.QMainWindow):
....
@block([self.list])
def updateList(self, *args):
//do things on self.list
Now I feel that could truly be useful! Except, @block([self.list]) has no idea what self is.
So, what I'm attempting to do, is that reasonable to assume I can do this? Is it possible, or am I chasing wild dragons? If it's possible, what's the correct way to attempt this?
You can't refer to the attribute values at class definition time, but you can use their names:
def block(*attrs):
def dec(fn):
@functools.wraps(fn)
def wrap(self,*args,**kwargs):
for a in attrs: getattr(self,a).blockSignals(True)
ret=fn(self, *args, **kwargs)
for a in attrs: getattr(self,a).blockSignals(False)
return ret
return wrap
return dec
It's a bit ugly to have to write
class Window(QtGui.QMainWindow):
@block("list1","list2")
def updateList(self, *args): # ...
with the string quotes and all, but it works.