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
)。我刚刚添加了它们。