Python 列表回调?
每次修改列表时,是否有办法使列表调用函数 例如:Python 列表回调?,python,list,callback,Python,List,Callback,每次修改列表时,是否有办法使列表调用函数 例如: >>>l = [1, 2, 3] >>>def callback(): print "list changed" >>>apply_callback(l, callback) # Possible? >>>l.append(4) list changed >>>l[0] = 5 list changed >>>l.pop(0
>>>l = [1, 2, 3]
>>>def callback():
print "list changed"
>>>apply_callback(l, callback) # Possible?
>>>l.append(4)
list changed
>>>l[0] = 5
list changed
>>>l.pop(0)
list changed
5
我几乎可以肯定这不能用标准列表来完成
我认为最干净的方法是编写自己的类来实现这一点(可能是从
列表
继承)。您必须对列表
进行子类化,并修改\uuuu setitem\uuuuu
class NotifyingList(list):
def __init__(self, *args, **kwargs):
self.on_change_callbacks = []
def __setitem__(self, index, value):
for callback in self.on_change_callbacks:
callback(self, index, value)
super(NotifyingList, self).__setitem__(name, index)
notifying_list = NotifyingList()
def print_change(list_, index, value):
print 'Changing index %d to %s' % (index, value)
notifying_list.on_change_callbacks.append(print_change)
正如评论中所指出的,它不仅仅是\uuuuu setitem\uuuu
class NotifyingList(list):
def __init__(self, *args, **kwargs):
self.on_change_callbacks = []
def __setitem__(self, index, value):
for callback in self.on_change_callbacks:
callback(self, index, value)
super(NotifyingList, self).__setitem__(name, index)
notifying_list = NotifyingList()
def print_change(list_, index, value):
print 'Changing index %d to %s' % (index, value)
notifying_list.on_change_callbacks.append(print_change)
构建一个实现
list
接口的对象,并在其自身中动态添加和删除描述符,以代替常规的列表机制,可能会更好地为您服务。然后,您可以将回调调用减少为描述符的\uuuu get\uuuuuu
、\uuu set\uuuuuuuu
、和\uuuu delete\uuuuuuu
借用@sr2222的建议,下面是我的尝试。(我将使用不带语法糖的decorator):
class NotifyingList(list):
def __init__(self, *args, **kwargs):
self.on_change_callbacks = []
def __setitem__(self, index, value):
for callback in self.on_change_callbacks:
callback(self, index, value)
super(NotifyingList, self).__setitem__(name, index)
notifying_list = NotifyingList()
def print_change(list_, index, value):
print 'Changing index %d to %s' % (index, value)
notifying_list.on_change_callbacks.append(print_change)
导入系统
_pyversion=sys.version\u info[0]
def回调_方法(func):
def通知(自我、*args、**kwargs):
对于_,在self中回调。_回调:
回调函数()
返回函数(self、*args、**kwargs)
返回通知
类别列表(列表):
extend=callback\u方法(list.extend)
append=callback\u方法(list.append)
remove=callback\u方法(list.remove)
pop=回调_方法(list.pop)
__delitem\uuuu=回调方法(列表)
__setitem\uuuuu=回调方法(列表)
__iadd=回调方法(列表)
__imul=回调方法(列表)
#如果我们对NotifyList进行切片,请注意返回一个新的NotifyList。
如果版本<3:
__setslice\uuuuu=回调方法(列表)
__delslice\uuuu=回调方法(列表)
def\uu getslice\uu(self,*args):
返回self.\uuuuu类(list.\uuuuu getslice.\uuuuuu(self,*args))
定义获取项目(自身,项目):
如果存在(项目,切片):
返回self.\uuuuu类\uuuuuu(列表.\uuuuuu获取项目\uuuuuuuuu(self,项目))
其他:
返回列表。获取项目(自我,项目)
定义初始化(self,*args):
列表。初始化(self,*args)
self.\u回调=[]
self.\u callback\u cntr=0
def寄存器_回调(自身,cb):
self.\u callbacks.append((self.\u callback\u cntr,cb))
自回叫\u cntr+=1
返回自我。\u回调\u cntr-1
def取消注册_回调(self,cbid):
对于枚举(self.\u回调)中的idx(i,cb):
如果i==cbid:
self.\u callbacks.pop(idx)
返回cb
其他:
一无所获
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
A=通知列表(范围(10))
def cb():
打印(“修改!”)
#注册回调
cbid=A.register\u回调(cb)
A.append('Foo')
A+=[1,2,3]
A*=3
A[1:2]=[5]
德拉[1:2]
#添加另一个回调。它们将按顺序调用(最老的优先)
def cb2():
打印(“修改2”)
A.register\u回调(cb2)
打印(“-”*80)
A[5]=“baz”
打印(“-”*80)
#取消注册第一个回调
A.unregister_回调(cbid)
A[5]=“qux”
打印(“-”*80)
印刷品(A)
打印(类型(A[1:3]))
打印(类型(A[1:3:2]))
打印(类型(A[5]))
最大的问题是,如果你意识到你忘了考虑一种特殊的方法,那就是添加1行代码。(例如,我刚才忘记了\uuu iadd\uuuu
和\uuu imul\uuuu
)
编辑
我已经稍微更新了代码,使其与py2k和py3k兼容。此外,切片将创建与父对象类型相同的新对象。请随意继续在这个食谱上戳洞,这样我可以做得更好。实际上,这看起来是一件非常整洁的事情……和
删除
和插入
,以及附加
和扩展
和排序
和反向
。。。这是一个很大的工作,但至少要添加一个非常简单的东西…@eryksun——我刚才也看到了python列表方法列表中的那些:)也许只需要修改\uuuu getattribute\uuuu
所有相关函数的列表…;)@pythonm:仅仅获取属性并不意味着您调用了该方法。我的意思是self.relevantgmethods:callback()中的if attr;return list.\uuuu getattribute\uuuu(self,attr)
我认为回调应该期望self、操作以及与操作相关的数据。否则,非常好。@sr2222--我认为回调应该不需要任何东西,尽管根据您的建议进行更改很容易(留给好奇的读者作为练习)。但是,向回调提供附加信息通常是通过闭包和lambda
完成的。事实上,我认为这就是lambda
在语言中如此重要的原因之一。例如,在tkinter
中就是这样做的。我只是想让它不仅仅是一个玩具,而是一个有用的东西。您的回调将希望能够知道列表以及列表中正在更改的内容。@sr2222--可能吧。但是,让它知道列表非常简单:A.add\u callback(lambda:callback(A))
。我想在不改变框架的情况下,让它知道正在发生的变化是有点棘手的。在2.x中还有\uuuu setslice\uuuu
和\uuu delslice\uuuuu
。我最初的答案也不见了\uuu iadd\uuuuuu
和\uuu imul\uuu
)。我刚刚添加了它们。