4

I simply wanted to know if you could call a function whenever a list is changed (item added to it). If anything it would look like this:

def listchanged():
    print("The list has been changed!")

list = ["apples","bananas"]
listevent(list,listchanged)

And in the shell you would append an item to the list and it would print "The list has been changed!"

Thanks!

  • 3
    What exactly do you need this for? There might be a better way. E.g., do you want to record each change, or just find out whether the list has been changed since some earlier point in time? And what are the methods the list might get changed by? – tobias_k Sep 24 '19 at 12:51
  • Not automatically, no. You have to make this sort of thing yourself, make sure you only change the list using functions you made that notify event listeners. – RemcoGerlich Sep 24 '19 at 12:59

3 Answers3

9

You can subclass list to print when changing the list.

Here's an example:

class EventList(list):

    def __setitem__(self, key, value):
        super(EventList, self).__setitem__(key, value)
        print("The list has been changed!")

    def __delitem__(self, value):
        super(EventList, self).__delitem__(value)
        print("The list has been changed!")

    def __add__(self, value):
        super(EventList, self).__add__(value)
        print("The list has been changed!")

    def __iadd__(self, value):
        super(EventList, self).__iadd__(value)
        print("The list has been changed!")

    def append(self, value):
        super(EventList, self).append(value)
        print("The list has been changed!")

    def remove(self, value):
        super(EventList, self).remove(value)

l = EventList(["apples","bananas"])
l.append('test')

Prints:

The list has been changed!

OR

Just compare lists:

old_list = ["apples","bananas"]
new_list = ["apples","bananas"]
newer_list = ["apples","bananas", "oranges"]

old_list == new_list #true
old_list == newer_list #false

This would work with no subclass as == compares if the lists have the same elements in the same indicies not if they are exactly the same by id or hash (in lamens). Just save the old one in a variable, then when you want to check just use this. (note: this does not provide a way for the print to be automatically called. It's just another way)

Jab
  • 26,853
  • 21
  • 75
  • 114
0
def listchanged():
    print("The list has been changed!")

lt = ["apples","bananas"]


def listevent(lt):
    prev_len=len(lt)

    lt.append("grapes")

    new_len=len(lt)
    
    if(prev_len!=new_len):
          listchanged()
listevent(lt)
Alex Ferguson
  • 107
  • 2
  • 10
  • The question is vague, may be try to make it clearer. – Alex Ferguson Sep 24 '19 at 12:58
  • It's not that vague, the answer is just "No." He doesn't want to change the list inside listevent, he wants listevent to get called whenever the list is changed (as an event listener). Doesn't exist in Python by default. – RemcoGerlich Sep 24 '19 at 13:00
  • 1
    It's not a good idea to name a list `list` since this is the name of the type which you bury below the new definition. – jottbe Sep 24 '19 at 14:06
0

I needed a container that can fire an event when a new item arrives, I've chosen deque and subclassed it this way:

In:

from collections  import  deque

class ArrivalDeque(deque):
    def append(self, value):
        super().append(value)
        return value
    
    def appendleft(self, value):
        super().appendleft(value)
        return value

    def extend(self, value):
        super().extend(value)
        return value
    
    def extendleft(self, value):
        super().extendleft(value)
        return value
    
pack = [66346.8, 45646.8, 89050.4, 67050.1]    

deq = ArrivalDeque([43253.8, 325325.2, 25425.2])
deq.extend(pack)

Out:

[66346.8, 45646.8, 89050.4, 67050.1]

Returns can be modified obviously, to call another function, or to tell length of iterable passed to extend() , for example.

P.S.: take note that sometimes doing this: deq.extend(reversed(pack)) might save the day.

gorx1
  • 31
  • 4