Is pypubsub message data sent by reference or value and why should I not modify the message data

342 Views Asked by At

I am using python 3. and would like to know if the message data attached to a pypubsub Sendmessage command is sent by reference or by value? It appears to be sent by reference but I was wondering if someone could verify that.

Also the documentation says "Message Immutability: message contents must be left unchanged by listeners, but PyPubSub does not verify this"

The code example below suggests that references to the message-data arguments are being sent and that modifying those data modify the original data (not a passed copy of the data) . Is there a reason why modifying the message data in the listener routine is a bad idea?

from pubsub import pub

class widget():    
    def __init__(self):
        self.thingy = [{'biz':0},{'baz':1},{'buz':2}]
        pub.subscribe(self.listen_for, 'wodget')

    def listen_for(self, arg1):
        print('wodget heard')
        print(self.thingy)
        print(arg1)

    def send_thingy(self):
        arg1 = self.thingy
        pub.sendMessage('widget',arg1=arg1)

class wodget():    
    def __init__(self):
        self.thongy = None
        pub.subscribe(self.listen_for, 'widget')

    # listen calendar               
    def listen_for(self, arg1):
        print('widget heard')
        print(arg1)
        self.thongy = arg1
        self.thongy[1]['baz']=99
        print(arg1)
        print(self.thongy)
        arg1 = self.thongy
        pub.sendMessage('wodget',arg1=arg1)

if __name__ == "__main__":

    aWidget = widget() 
    aWidget.send_thingy()

    aWodget = wodget()   
    aWidget.send_thingy()
1

There are 1 best solutions below

0
On

A simple script seems to suggest the behavior of modifying objects using pypubsub callbacks is consistent with normal python behavior which makes sense to me, as pypubsub is just function callbacks. See below.

Also see: How do I pass a variable by reference? for a discussion of immutability.

from pubsub import pub


class TestClass():
    def __init__(self):
        self.item_1 = 10.0
        self.item_2 = [1,2,3]
        self.item_3 = {1:[3,4,5], 2:[6,7,8]}

    def change_values(self):
        self.item_1 += 1
        self.item_2 = [v + 1 for v in self.item_2]
        self.item_3 = {k:[v + 1 for v in self.item_3[k]] for k in self.item_3}

    def print_values(self):
        print(self.item_1)
        print(self.item_2)
        print(self.item_3)
        # print('\n')


def receive_class(an_object):
    print('INSIDE - BEFORE')
    an_object.print_values()
    an_object.change_values()
    print('INSIDE - AFTER')
    an_object.print_values()


def receive_variable(a_variable):
    print('INSIDE - BEFORE')
    print(a_variable)
    a_variable += 1.0
    print('INSIDE - AFTER')
    print(a_variable)


def receive_list(a_list):
    print('INSIDE - BEFORE')
    print(a_list)
    a_list[0] += 1
    a_list[1] += 1
    a_list[2] += 1
    print('INSIDE - AFTER')
    print(a_list)


if __name__ == "__main__":
    pub.subscribe(receive_class, "test_topic_class")
    pub.subscribe(receive_variable, "test_topic_variable")
    pub.subscribe(receive_list, "test_topic_list")

    ### TEST 1
    print('-----CLASS TEST')
    myclass = TestClass()
    print('OUTSIDE - BEFORE')
    myclass.print_values()
    pub.sendMessage("test_topic_class", an_object=myclass)
    print('OUTSIDE - AFTER')
    myclass.print_values()

    ### TEST 2
    print('-----VARIABLE TEST')
    avar = 100.0
    print('OUTSIDE - BEFORE')
    print(avar)
    pub.sendMessage("test_topic_variable", a_variable=avar)
    print('OUTSIDE - AFTER')
    print(avar)

    ### TEST 3
    print('------LIST TEST')
    alist = [1.0, 2.0, 3.0]
    print('OUTSIDE - BEFORE')
    print(alist)
    pub.sendMessage("test_topic_list", a_list=alist)
    print('OUTSIDE - AFTER')
    print(alist)

OUTPUT:

-----CLASS TEST
OUTSIDE - BEFORE
10.0
[1, 2, 3]
{1: [3, 4, 5], 2: [6, 7, 8]}
INSIDE - BEFORE
10.0
[1, 2, 3]
{1: [3, 4, 5], 2: [6, 7, 8]}
INSIDE - AFTER
11.0
[2, 3, 4]
{1: [4, 5, 6], 2: [7, 8, 9]}
OUTSIDE - AFTER
11.0
[2, 3, 4]
{1: [4, 5, 6], 2: [7, 8, 9]}
-----VARIABLE TEST
OUTSIDE - BEFORE
100.0
INSIDE - BEFORE
100.0
INSIDE - AFTER
101.0
OUTSIDE - AFTER
100.0
------LIST TEST
OUTSIDE - BEFORE
[1.0, 2.0, 3.0]
INSIDE - BEFORE
[1.0, 2.0, 3.0]
INSIDE - AFTER
[2.0, 3.0, 4.0]
OUTSIDE - AFTER
[2.0, 3.0, 4.0]