列表回调? [英] List callbacks?

查看:98
本文介绍了列表回调?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

每次修改列表时,是否有任何方法使列表调用函数?



例如:

 >>> l = [1,2,3] 
>> ; def callback():
printlist changed
>>> apply_callback(l,callback)
>>> l.append(4)
更改的列表
>>> l [0] = 5
更改列表
& >>> l.pop(0)
列表已更改
5


解决方案

借用@ sr2222的建议,这里是我的尝试。 (我将使用没有语法糖的装饰器):

  import sys 

_pyversion = sys .version_info [0]

def callback_method(func):
def notify(self,* args,** kwargs):
for _,callback in self._callbacks:
callback()
return func(self,* args,** kwargs)
return notify

class NotifyList(list):
extend = callback_method list.extend)
append = callback_method(list.append)
remove = callback_method(list.remove)
pop = callback_method(list.pop)
__delitem__ = callback_method __delitem__)
__setitem__ = callback_method(list .__ setitem__)
__iadd__ = callback_method(list .__ iadd__)
__imul__ = callback_method(list .__ imul__)

#返回一个新的NotifyList如果我们切片。
if _pyversion< 3:
__setslice__ = callback_method(list .__ setslice__)
__delslice__ = callback_method(list .__ delslice__)
def __getslice __(self,* args):
return self .__ class __(list。 __getslice __(self,* args))

def __getitem __(self,item):
if isinstance(item,slice):
return self .__ class __(list .__ getitem __ ,item))
else:
return list .__ getitem __(self,item)

def __init __(self,* args):
list .__ init __(self, * args)
self._callbacks = []
self._callback_cntr = 0

def register_callback(self,cb):
self._callbacks.append ._callback_cntr,cb))
self._callback_cntr + = 1
return self._callback_cntr - 1

def unregister_callback(self,cbid):
for idx, i,cb)in enumerate(self._callbacks):
if i == cbid:
self._callbacks.pop(idx)
return cb
else:
返回无


如果__name__ =='__main__':
A = NotifyList(range(10))
def cb():
print Modify!)

#register a callback
cbid = A.register_callback(cb)

A.append('Foo')
+ = [1,2,3]
A * = 3
A [1:2] = [5]
del A [1:2]

#Add另一个回调。它们将按顺序调用(最早的)
def cb2():
print(Modify2)
A.register_callback(cb2)
print 80)
A [5] ='baz'
print( - * 80)

#unregister第一个回调
A.unregister_callback(cbid)

A [5] ='qux'
打印( - * 80)

打印(A)
打印:3]))
print(type(A [1:3:2]))
print(type(A [5]))
pre>

这是伟大的事情,如果你意识到你忘了考虑一个特定的方法,它只是一行代码添加它。 (例如,我刚才忘了 __ iadd __ __ imul __



EDIT



我已将代码稍微更新为py2k和py3k兼容。此外,切片创建一个与父类型相同类型的新对象。请随时在这个食谱继续戳洞,所以我可以让它更好。这实际上看起来像一个非常整洁的事情有手头...


Is there any way to make a list call a function every time the list is modified?

For example:

>>>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

解决方案

Borrowing from the suggestion by @sr2222, here's my attempt. (I'll use a decorator without the syntactic sugar):

import sys

_pyversion = sys.version_info[0]

def callback_method(func):
    def notify(self,*args,**kwargs):
        for _,callback in self._callbacks:
            callback()
        return func(self,*args,**kwargs)
    return notify

class NotifyList(list):
    extend = callback_method(list.extend)
    append = callback_method(list.append)
    remove = callback_method(list.remove)
    pop = callback_method(list.pop)
    __delitem__ = callback_method(list.__delitem__)
    __setitem__ = callback_method(list.__setitem__)
    __iadd__ = callback_method(list.__iadd__)
    __imul__ = callback_method(list.__imul__)

    #Take care to return a new NotifyList if we slice it.
    if _pyversion < 3:
        __setslice__ = callback_method(list.__setslice__)
        __delslice__ = callback_method(list.__delslice__)
        def __getslice__(self,*args):
            return self.__class__(list.__getslice__(self,*args))

    def __getitem__(self,item):
        if isinstance(item,slice):
            return self.__class__(list.__getitem__(self,item))
        else:
            return list.__getitem__(self,item)

    def __init__(self,*args):
        list.__init__(self,*args)
        self._callbacks = []
        self._callback_cntr = 0

    def register_callback(self,cb):
        self._callbacks.append((self._callback_cntr,cb))
        self._callback_cntr += 1
        return self._callback_cntr - 1

    def unregister_callback(self,cbid):
        for idx,(i,cb) in enumerate(self._callbacks):
            if i == cbid:
                self._callbacks.pop(idx)
                return cb
        else:
            return None


if __name__ == '__main__':
    A = NotifyList(range(10))
    def cb():
        print ("Modify!")

    #register a callback
    cbid = A.register_callback(cb)

    A.append('Foo')
    A += [1,2,3]
    A *= 3
    A[1:2] = [5]
    del A[1:2]

    #Add another callback.  They'll be called in order (oldest first)
    def cb2():
        print ("Modify2")
    A.register_callback(cb2)
    print ("-"*80)
    A[5] = 'baz'
    print ("-"*80)

    #unregister the first callback
    A.unregister_callback(cbid)

    A[5] = 'qux'
    print ("-"*80)

    print (A)
    print (type(A[1:3]))
    print (type(A[1:3:2]))
    print (type(A[5]))

The great thing about this is if you realize you forgot to consider a particular method, it's just 1 line of code to add it. (For example, I forgot __iadd__ and __imul__ until just now :)

EDIT

I've updated the code slightly to be py2k and py3k compatible. Additionally, slicing creates a new object of the same type as the parent. Please feel free to continue poking holes in this recipe so I can make it better. This actually seems like a pretty neat thing to have on hand ...

这篇关于列表回调?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆