Search code examples
pythonpython-2.7ipcmessage-passing

How to insert items periodically to the List of another python script?


I have an issue updating the items of List L[] from another Python script file. below are the two simple files that I have now,, any help/suggestion/advise will be highly appreciated.

script1.py

import time, threading
L=[]
def first():
    if len(L)!=0:
       x = L.pop()
       print 'The element', x, 'left the list L'
    else:
         print 'L is empty now ...'
    threading.Timer(10, first).start()

first() 

script2.py

from __main__ import *
import time
import script1
c = 1
def pass_arg():
    global c
    c+=1
    L.append(c)
    print 'will pass value to the list L of script1.py'
    threading.Timer(10, pass_arg).start()

pass_arg()

The issue that I face is that sript2 could not reach the defined list L of script1. Also, the script2 starts to follow all the running function/s of script1!?

Many thanks in advance,

After editing the previous code based on the recommendations, now I have the following scripts:

script1.py

from __main__ import *
import time, threading

class ListHolder: 
  def __init__(self):
    self.L = [] 

  def first(self):
    if len(self.L)!=0:
       x = self.L .pop()
       print 'The element', x ,'left the list L'
    else:
        print 'L is empty now ...'
    threading.Timer(10, self.first).start()

R = ListHolder()
R.first()

script2.py

from __main__ import *
import time, threading
from script1 import ListHolder

c = 1

X = ListHolder()

def pass_arg():
    global c
    c+=1
    X.L.append(c)
    print X.L
    print 'will pass value to the list L of script1.py'
    threading.Timer(10, pass_arg).start()

pass_arg()

The main issue now is that the new added items by script2.py are not passed to script1.py, hence the List in script1.py remains empty all the time and the change is not reflected on the script1 list. Any suggestions?


Solution

  • Python doesn't have true global variables, or at least they don't work the way you are using them. For what it's worth there a bunch of other answers on Stack Overflow like Using global variables in a function other than the one that created them that have answers detailing how to get around the default behavior, but it's all kind of hacky and not really what Python wants you to do in most cases.

    What you want to do is use a class here.

    class ListHolder: 
          self.L=[] 
    

    Then you will be able to access ListHolder.L without there being any troubles. In the long run you don't want to use global vars anyway, so python is encouraging you to do the right thing here.

    If you think that you have code that's self contained, and it should go in it's own file, a class or module is usually the right bet in Python.

    Update in Response to OP's Update: First, let's go line by line through your scripts and make some comments.

    We will start with script2.py

    from __main__ import * #Don't need this. 
    import time, threading #We don't need threads to do this. 
    from script1 import ListHolder #This EXECUTES code in script1.py 
    
    c = 1 #fine
    
    X = ListHolder() #Good 
    
    def pass_arg():
        global c #not necessary 
        c+=1 #fine 
        X.L.append(c) #fine
        print X.L #fine 
        print 'will pass value to the list L of script1.py' #You already did that. 
        threading.Timer(10, pass_arg).start() #You don't need this. 
                                              #furthermore it will execute forever and
                                              #die when it blows the stack. 
    
    pass_arg()  #this is fine 
    

    Here is Script2.py

    from __main__ import * #this is not needed. 
    import time, threading #We aren't using threads. Why import threads? 
    
    class ListHolder: 
      def __init__(self):
        self.L = [] #This should be ok, but we could have also have initialized this 
                    #in class scope rather than init. 
    
      def first(self):
        if len(self.L)!=0: 
           x = self.L .pop()
           print 'The element', x ,'left the list L'
        else:
            print 'L is empty now ...'
        threading.Timer(10, self.first).start() #This will execute forever. 
    
    R = ListHolder() #as these are in "file" scope
    R.first()  #they will execute when imported! 
    

    So let's simplify this into a better format.

    Script2b.py
    from script1b import ListHolder 
    
    c = 1 #fine
    
    X = ListHolder() #Good 
    
    def pass_arg(z): #Functions need arguments. 
        z+=1 #we should use function scope vars 
             #instead of mutating global scope. 
        X.L.append(c) #fine
        print X.L #fine 
        return z #return locally mutated data
                 #instead of mutating global scope. 
    
    for x in range(1,10):
      c = pass_arg(c)  #this is fine 
    
      X.popMe()   
    

    script1b.py

    class ListHolder: 
      def __init__(self):
        self.L = [] #This should be ok, but we could have also have initialized this 
                    #in class scope rather than init. 
    
      def popMe(self):
        if len(self.L)!=0: 
           x = self.L .pop()
           print 'The element', x ,'left the list L'
        else:
            print 'L is empty now ...' 
    

    Now since you kept trying to use threads, I suspect you are trying to do something a little different than what your post says. I suspect you are under the impression you can run both scripts simultaneously and communicate between the two scripts using the threading interface.

    Not so!

    A few points to consider:

    1) You have written one script with threads.

    This will not result in parallel execution, and the scripts will not operate independent of one another. You are just yielding control between the scripts. Threading is best for asynchronous operations - it does not result in parallel execution or independent state. Think about situations like event handlers and callbacks.

    2) Python does not inherently support Parallelism Pe Se:

    Python isn't a great choice for Parallel programming. You can use the "Process" class to kick off independent processes, and then manage them externally. However, "Process" doesn't understand the processes are Python programs, and you wont be able to directly influence their variables. The way you would do this is to run small processes, and return values for the central process to reason about. Think OpenGL shaders.

    3) You are not managing state between threads correctly.

    The execution time of threads cannot be guaranteed. Your original script may work sometimes, and not work other times. You need to uses locks/mutexes to prevent data races. If you truly intend to use threads, you need to think hard about how you protect the data from dataraces. If you need help with that you should start a new question focusing on that.

    4) You almost certainly don't need threads.

    Based on your level of programming knowledge, I am guessing you don't actually require threads for your task. Most times programmers should avoid using explicit threading until it is absolutely unavoidable.