Search code examples
pythontwistedtwisted.internet

twisted defer make the assignment of class instance variables is invalid


I have a class A with two methods, method_one which uses a defer and method_two , in callback function I set a value to self.value and add it to defer's callback chain. but after that the self.value is still the original value in method_two. in short, the assignment of self.value in callback function is invalid.

from twisted.internet import utils, reactor
class A(object):

    def __init__(self):
        self.value = []

    def method_one(self):
        d = utils.getProcessOutput('/bin/sh', ('-c', 'ls /home')) # return a defer
        def set_self_value(result):
            self.value = result.split()  # assign result.split() to self.value
        d.addCallback(set_self_value)

    def method_two(self):
        print self.value  # it is still [] rather than result

a = A()
a.method_one()
a.method_two()
reactor.run()

output:
[]  # i expect self.value is ['lost+found', 'user']
lost+found
user

thanks in advance :-)


Solution

  • The issue is that as the method_one is deferred, so, instead of calling set_self_value right away it first moves on to the next step a.method_two(), hence as at that time the value is not yet set you get an empty list.

    To make sure method_two is called after method_one add it to the callback chain:

    import twisted
    from twisted.internet import utils
    from twisted.internet import reactor
    
    
    class A(object):
    
        def __init__(self):
            self.value = []
    
        def method_one(self):
            d = utils.getProcessOutput('/bin/sh', ('-c', 'ls /home'))
            def set_self_value(result):
                print 'called set'
                self.value = 100
            d.addCallback(set_self_value)
            d.addCallback(self.method_two)
    
        def method_two(self, *args): # *args required to handle the result
            print 'called two'
            print self.value
    
    def main():
        a = A()
        a.method_one()
    
    
    reactor.callWhenRunning(main)
    reactor.run()
    

    Output:

    called set
    called two
    100