Python: Change variable value from another thread - python

Why does the value of my_string not change?
I'm running two threads from two different modules, and module 2 accesses the "set_string" of module 1 in order to change the value of "my_string", but when module 1 prints the string, its empty.
First module:
from threading import Thread
import Module2 as M2
import time
my_string = ""
def set_string(string):
global my_string
my_string = string
def mainloop1():
global my_string
while True:
print("Module 1: ", my_string)
time.sleep(1)
if __name__ == '__main__':
thread = Thread(target=M2.mainloop2)
thread.start()
mainloop1()
Second module:
import Module1 as M1
import time
import random
def mainloop2():
while True:
string = str(random.randint(0, 100))
print("Module 2: ", string)
M1.set_string(string)
time.sleep(1)

It's because the methods are implemented in different modules and there are no truly global variables in python; the set_string referenced in Module2 is updating the my_string variable in its globals()['M1'] name where-as Module1 is updating the my_string variable stored directly in globals()['my_string'].
Note that if you move your definition of mainloop2 into Module1, update the imports, and the Thread call then you get your expected behavior, indefinite execution order and all.

Related

Python relative import variable name error [duplicate]

I created two files, and when I run a.py, result is {'1': '1'}, it's correct. however, running b.py, the result is none. How can I get the value of requests from b.py?
a.py:
requests = {}
def set_value():
global requests
requests["1"] = "1"
if __name__ == "__main__":
set_value()
print(requests)
b.py:
import a
def get_value():
print(a.requests)
if __name__ == "__main__":
get_value()
if __name__ == "__main__": means that the code following it will only be executed when the file is called explicitly with python3 filename.py from the command line. Since you are simply importing your file and not executing it, the global variable is never set.
Also, python variables are all "global" variables when declared outside of a function, and the global keyword is only needed when you want to declare a global variable inside of a function.
To fix this, change a.py to the following:
requests = {}
def set_vale():
requests["1"] = "1"
set_vale()

How to update a list from an imported module once imported?

test.py
import threading
a_list = []
def a():
while True:
a_list.append("A")
threading.Thread(target=a).start()
test1.py
import test
from test import a_list
import time
while True:
print(a_list)
time.sleep(1)
if I import the file "test" and infinitely append "A" into a list and use "test1" to print the values, for some reason the values WILL NOT update for test1
How can I make test1 recognise that the list has been updated from file "test" and print it out using the file "test1"
I rushed this code to share in here, I am sorry about that. Some help would be nice. I tried googling it but I couldn't find anything
You forgot global in your function:
import threading
a_list = []
def a():
global a_list
while True:
a_list.append("A")
threading.Thread(target=a).start()
Althougth I recommend against such code.
Beware: "Here be dragons"

Sharing Global variables in python

I have 2 files a.py and b.py as follows:
a.py
import b.py
Test="abc"
def main(args):
global Test
if args.target=="this":
Test="klm"
b.fun()
#rest of the body which I intend to execute only once
#hence I cannot call main() again
if __name__ == "__main__":
#some arguments are parsed
args = parser.parse_args()
main(args)
b.py
import a
print a.Test
EDIT: Output:
python a.py
abc
So basically my question is why is the Test variable not getting updated in b.py and how can I make this work? Thanks.
import a
a.main()
print a.Test
a.Test = "new Value"
print a.Text
You never invoke the main function. When you import a module, __name__ is not "__main__", so your main() never runs. When you run a.py directly it will run main()
Added due to question edit:
You need to consider the ordering of the imports execution. Consider these working files.
a.py
print("Entering a")
import argparse
import b
Test="abc"
print("Id of Test: ", id(Test))
def main(args):
global Test
if args.target=="this":
Test="klm"
b.fun()
#rest of the body which I intend to execute only once
#hence I cannot call main() again
if __name__ == "__main__":
#some arguments are parsed
print('Entering main')
parser = argparse.ArgumentParser()
parser.add_argument('--target', dest='target', type=str)
args = parser.parse_args()
main(args)
b.py
print("Entering b")
import a
print a.Test
def fun():
pass
The console produces the following:
$ python a.py
Entering a
Entering b
Entering a
('Id of Test: ', 40012016L)
abc
('Id of Test: ', 40012016L)
Entering main
The problem is, when you import a python module/file, you will immediately execute all the statements in that module. As such, you have a problem with your dependencies (aka imports), because b is importing a before the value of Test is 'corrected' and then immediately acting on this.
Consider two changes. First, introduce a third file config.py that contains this configuration information and that b does not import a. Second, move all your statements that require this config in b into functions that are called/bootstrapped by a, as obviously intended.
Previous answer:
I have a solution demonstrating the issue, by only modifying b.py
def fun(): # Added because your main calls this. An error?
pass
from a import Test, main
import a
print Test # prints 'abc'
print a.Test # prints 'abc'
main()
print Test # prints 'abc'
print a.Test # prints 'klm'
Within the python interpretor, I can produce the following:
>>> import b
abc
abc
abc
klm
In your code, you create a new variable called Test with the command from a import Test that points to the original string object. You actually want to access the Test variable owned by the module a.
In a.py you run main in the if statement:
if __name__ == "__main__":
main()
Only executes main() if that is the main script. When you import the module all the code in the if block is not run because it is not the main script. To have the main method be called remove the if statement or just call main in b.py.

global name logger is not defined thru classes?

I cant get logger as a global name... I tried it inside a normal script, and later trying to debug inside the python cli, but its out of my reach apparently...
(as you will notice, I tried to define logger global everywhere, but also without that, no success)
Inside the python cli-program:
import time
import datetime
import subprocess
import re
import glob
import logging
from daemon import runner
from lockfile import LockTimeout
import RPIO
import picamera
import atexit
#From here, it should be global right?
global logger
logger = logging.getLogger("DoorcamLog")
import DoorcamExample
doorcam=DoorcamExample.Doorcam()
Error returned:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "DoorcamExample.py", line 28, in __init__
logger.info('Doorcam started capturing')
NameError: global name 'logger' is not defined
DoorcamExample.py:
#!/usr/bin/python
import sys
import os
if os.geteuid() != 0:
# This works perfect on a Raspbian system because there's no rootpassword required
os.execvp("sudo", ["sudo"] + sys.argv)
print('to far!') #This should NEVER be reached, there is something wrong...
sys.exit(1)
import time
import datetime
import subprocess
import re
import glob
import logging
from daemon import runner
from lockfile import LockTimeout
import RPIO
import picamera
import atexit
class Doorcam:
global logger
def __init__(self):
logger.info('Doorcam started capturing')
self.pollLightFile='/var/tmp/picam-pollLight'
atexit.register(self.stopListening)
def socket_callback(self, socket, val):
vals=val.split()
if len(vals) == 0 or len(vals) > 4:
number=1
notify=True
trigger='Socket'
triggernotify='Socket (value %s)'%val
elif len(vals) == 1:
number=int(vals[0])
notify=True
trigger='Socket'
triggernotify='Socket (value %s)'%val
elif len(vals) == 2:
number=int(vals[1])
notify=True
trigger=vals[0]
triggernotify=vals[0]
elif len(vals) == 3:
number=int(vals[1])
trigger=vals[0]
triggernotify=vals[0]
notify=self.boolval(vals[2])
elif len(vals) == 4:
number=int(vals[2])
trigger=vals[0]
triggernotify=vals[0], [1]
notify=self.boolval(vals[3])
socket.send('self.upload(self.shot(filename=self.filename, number=number, trigger=trigger), notify=notify,trigger=triggernotify)')
RPIO.close_tcp_client(socket.fileno())
def startListening(self,channel,port=8080, threaded=True):
#RPIO.add_interrupt_callback(channel, self.gpio_callback, pull_up_down=RPIO.PUD_DOWN, debounce_timeout_ms=1000)
RPIO.add_tcp_callback(port, self.socket_callback)
RPIO.wait_for_interrupts(threaded=threaded)
def stopListening(self):
logger.info('Stop listening')
RPIO.stop_waiting_for_interrupts()
global logger
"Global" variables are only global within a single module, so your DoorcamExample.py doesn't have access to logger that you defined in some other module.
In this case, you don't need a global variable, because the logging module already maintains a truly global (i.e., visible from all modules) registry of loggers. So if you do logging.getLogger("DoorcamLog") in any of your modules, you'll get a reference to the same logger.
You don't need a program-wide global variable in this case. The logging module tracks all loggers created via calls to getLogger, so as long as you use the same name, you'll get the same logging object. So calls to logging.getLogger("DoorcamLog") will return the same object in both scripts.
As BrenBarn commented, in Python, "global" only refers to the current module's namespace - hopefully, since you wouldn't want a module to depend on some name being defined in the importing module's namespace.
Also, the "global" keyword is only meaningful in a function - every name defined at the module's top-level is by definition global to the module - and it's only useful if you actually want to rebind that name within the function (so Python knows you're not creating a local variable instead).
wrt/ loggers naming, the simplest and more effective solution is to create a logger for each module and just pass the current module's name (ie the 'magic' variable __name__), except for executable scripts (which will be named "main").

Import at file level inside a function? (Python 2)

Is it possible to do something like this?
def loadModules():
import time
from myModule import *
def runFunction():
try:
print str(time.time())
print myFunction() # myFunction is in myModule (myModule.myFunction)
except NameError:
raise RuntimeError("Module was not initialized. Call loadModules() first.")
if (__name__ == "__main__"):
# this should fail
try:
runFunction()
except RuntimeError:
print "Exception raised as expected."
loadModules()
runFunction() # it should work now
This will not work as expected because importing the modules inside the loadModules function will not declare them at a file level.
For modules like time I could add a global time statement after the import. However, how can I accomplish this for a situation where the items imported are unknown, as in from myModule import *? I won't automatically know the name of every function in myModule. And even if I did, that'd be an ugly global statement.
Essentially, can I basically take all local variables and make them global?
EDIT: This seemed to work in test code:
def test():
import time
global time
print "Inside test function: %s" % str(time.time())
test()
print "outside function: %s" % str(time.time())
This also worked:
def test():
from time import time
global time
print "Inside test function: %s" % str(time())
test()
print "outside function: %s" % str(time())
This however did not work:
def test():
import time
print "Inside test function: %s" % str(time.time())
test()
print "outside function: %s" % str(time.time())
This is a horrible idea, even if it could ever work, which it couldn't.
Putting a global statement after the import will have exactly zero effect. The only thing that does is mark that name as global within the current scope. Once the function returns, the caller will still have no knowledge of the imported names.
In any case, you shouldn't ever be using from MyModule import * anyway.

Categories

Resources