Function not changing global variable - python

my code is as follow:
done = False
def function():
for loop:
code
if not comply:
done = True #let's say that the code enters this if-statement
while done == False:
function()
For some reason when my code enters the if statement, it doesn't exit the while loop after it's done with function().
BUT, if I code it like this:
done = False
while done == False:
for loop:
code
if not comply:
done = True #let's say that the code enters this if-statement
...it exits the while loop. What's going on here?
I made sure that my code enters the if-statement. I haven't run the debugger yet because my code has a lot of loops (pretty big 2D array) and I gave up on debugging due to it being so tedious. How come "done" isn't being changed when it's in a function?

Your issue is that functions create their own namespace, which means that done within the function is a different one than done in the second example. Use global done to use the first done instead of creating a new one.
def function():
global done
for loop:
code
if not comply:
done = True
An explanation of how to use global can be found here

done=False
def function():
global done
for loop:
code
if not comply:
done = True
you need to use the global keyword to let the interpreter know that you refer to the global variable done, otherwise it's going to create a different one who can only be read in the function.

Use global, only then you can modify a global variable otherwise a statement like done = True inside the function will declare a new local variable named done:
done = False
def function():
global done
for loop:
code
if not comply:
done = True
Read more about the global statement.

Using a class rather than global:
Another way to handle (not use) global variables is to wrap the functions and variables you wish to be global in a class.
While this is a little heavy for this specific case - classes add a host of functionality and flexability to the project. (Personally) highly recommended.
For example:
class Processor():
"""Class container for processing stuff."""
_done = False
def function(self):
"""A function which processes stuff."""
# Some code here ...
self._done = True
# See the flag changing.
proc = Processor()
print('Processing complete:', proc._done)
proc.function()
print('Processing complete:', proc._done)
Output:
Processing complete: False
Processing complete: True

Related

Using the same hotkey for two different purposes in Python

Using pythons keyboard library,
I have two function definitions:
def start_tracking():
*code to start tracking time*
def end_tracking():
*code to stop tracking time*
I then want to use the same hotkey (e.g. F1) to invoke function 1 (start tracking time) on the first press and then function 2 (end tracking time) on the subsequent press. If I press the hotkey again after that, it should repeat the process.
Basically I want to use the same hotkey to track time and stop tracking time.
Here's what a working solution to start tracking time and stop tracking time using two different hotkeys looks like:
keyboard.add_hotkey("F1", start_tracking)
keyboard.add_hotkey("F2", end_tracking)
How can I accomplish the same thing with only one key (F1)?
I don't want to use a while loop because it slows down performance quite a bit.
Consider using a class variable or global variable as a flag. Such that:
class tracker():
def __init__(self):
self.start_flag = True <- Init class variable
def tracking(self):
if self.start_flag:
start_tracking()
self.start_flag = False #<- class variable toggling
else:
stop_tracking()
self.start_flag = True #<- class variable toggling
if name == '__main__'
x = tracker()
x.tracking() # starts tracker
time.sleep(5)
x.tracking() # stops tracker
Without more context on what your program is doing I can't say which is better. Typically globals should be avoided though. Simply put, you need a way to toggle which function is run. PS copypasting wont work. You will need to setup the class etc for proper usage. especially with where and how you defined start/stop. I would guess you are using globals but typically this should be avoided.
Solution:
def started():
start_tracking()
keyboard.remove_hotkey("F1")
keyboard.add_hotkey("F1", ended)
def ended():
end_tracking()
keyboard.remove_hotkey("F1")
keyboard.add_hotkey("F1", started)
#Hotkey
keyboard.add_hotkey("F1", started)
Basically I switch between the two events every time I press the hotkey by calling two functions in an alternating fashion.

Shorten a repeating exit flag for functions

I would like to exit a function by pressing a button using the return statement in the if statement. To write these lines again and again and again is not really what I like. That's why I am basically looking for a function that tells the parent function to return.
Obviously I can't use the return statement in a function and just execute the function where I want to check the variable, although that would be the nicest way I could imagine.
I want to explain it in a loop, but please keep in mind that's not where I want to use it. The usage is for automated processes which should have many exit points.
import keyboard, time
RedFlag = False
def set_RedFlag():
global RedFlag
RedFlag = True
keyboard.add_hotkey("end", set_RedFlag)
PauseFlag = False
def set_PauseFlag():
global PauseFlag
print(PauseFlag)
if PauseFlag == False:
PauseFlag = True
else:
PauseFlag = False
keyboard.add_hotkey("space", set_PauseFlag)
def task():
for i in range(30):
print("test",i)
time.sleep(1)
# Flags
if RedFlag == True: # exitpoint
return
while PauseFlag == True: # pause the script
time.sleep(1/6)
task()
Really relevant is the if statement after #Flags. Especially with the while statement I would have to repeat multiple lines. I would love to have this in one single word as if it was a function.
Edit:
More about the "what for?":
I would like to run a macro and later maybe other tasks. For example writing the odd numbers from 1 to 511. And I want to be able to stop or pause it at any given time.
I forgot to mention, that I tried using the multiprocessing module, since I could terminate the task there. Sadly it is not an option for me not only because the starting time of a process is a bit too long for me, also I am learning a bit about kivy and I know it get's complicated when I want to start another process while using kivy.

I'm having trouble with setting a timer to a recursive function that I want to stop running for too long in python

this is the first time I am reaching out with a question so hopefully I get the format right.
I am trying to limit the running time of my function (lets call it 'recursive_tsp_function') that is called from inside another function. This function recursive_tsp_function sometimes (not always) for unknown reasons keeps running infinitely.
CONTEXT:
Already, I tried implementing some sort of time checks like this
def recursive_tsp_function(parameters)
start = time.time()
... (function here)
now = time.time()
if (now - start) > max_time:
return
... (function continues)
But for some reason my kernel in debugging mode keeps running the recursive function infinitely until I manually pauze the running and go on step by step in the debugger and than it does register the time checks and than stops the function like it should.
NOW:
Because that approach didn't work I looked a better method online and came upon working with threads. I now have the following method based an a simple online example:
'Countdown' is my timer function (in the same file as the 'above_function').
The structure of my function above 'above_function' you can see below (note that it threads the timer).
Also I added a 'check' function to the same file as the above_function that checks whether the timer has run out. I did this because there was a problem with referring to the global variable my_timer from the recursive_tsp_function which is located in a different file (I would think my_timer being a global variable would make it accessible from other functions but anyway that seems to be resolved for now)
def countdown(max_time_timer):
global my_timer
my_timer = max_time_timer
for x in range(max_time_timer):
my_timer = my_timer - 1
time.sleep(1)`
def check():
global my_timer
if my_timer ==0:
return False
else: return True
def above_function(...):
...
countdown_thread = threading.Thread(target = countdown(10))
countdown_thread.start()
route = recursive_tsp_function(parameters)
...
return route
And than in a different file I have the recursive_tsp_function that would look something like this where I routinely run the check function from above and check whether my_timer is 0 yet:
def recursive_tsp_function(variables):
...
if not check():
return
...
return recursive_tsp_function(variables)
The PROBLEM that I have with this setup is there seems to be no threading taking place, the timer first runs out and only than the function recursive_tsp_function would run. Naturally this function stops immediately because the timer is already on 0.
Thank you for being patient with my long explanation. If anybody got tips on how to tackle a timer on a function like this I would be very grateful.
you should create the thread like this.
# target is the callable object
# args is the argument tuple for the target invocation
countdown_thread = threading.Thread(target = countdown, args=(10,))
What if you try
maxtime = int(input("What is the time for the timer?"))
import time
time_went = 0
for i in maxtime:
time_went = i
time.sleep(1)
And then instead of using time_went == 0 you can use time_went == maxtime?

Quitting a Python program

I am trying to quit a python program by calling sys.exit() but it does not seem to be working.
The program structure is something like:
def func2():
*does some scraping operations using scrapy*
def func1():
Request(urls, callbakc=func2)
So, here, func1 is requesting a list of URLs and the callback method, func2 is being called. I want to quit the execution of the program if something goes wrong in func2
On checking the type of the object in func1 I found its and http.Request object.
Also, since I am using scrapy, whenever I call sys.exit() in func2, the next url in the list is called and the program execution continues.
I have also tried to use a global variable to stop the execution but to no avail.
Where am I going wrong?
According to the How can I instruct a spider to stop itself?, you need to raise CloseSpider exception:
raise CloseSpider('Done web-scraping for now')
Also see:
Running Scrapy tasks in Python
sys.exit() would not work here since Scrapy is based on twisted.
Even if we don't know how to completely stop, Python's mutable-object default binding "gotcha" can help us skip all callbacks from a certain point on.
Here is what you can do:
First, create a function generating wrapping other callback functions with condition. It's second argument cont is going to be bound to a mutable object (list) so we can affect all callbacks after creating them.
def callback_gen(f, cont=[True]):
def c(response):
if cont[0]:
f(response, cont=cont)
else:
print "skipping" # possibly replace with pass
return c
Now make some testing functions:
def func2(response, cont=None):
print response
print cont
# this should prevent any following callback from running
cont[0]=False
def func3(response, cont=None):
print response
print cont
And now create two callbacks the first one is func2 which prevents the following ones from running.
f2 = callback_gen(func2)
f3 = callback_gen(func3)
f2("func2")
f3("func3")
I like it :)

Setting Variable in Python Callback

So I have a small python program that is spread out across a few classes. In my main class, I tell my title screen class to display and then wait for input. If the input it gets is 'q' it calls back to my main class telling it to set it's stop flag to true. Otherwise, it just loops.
This is the callback I give to my title screen:
def quit():
stopped = True
stopped is set to False outside of the callback. The callback is registered fine, and goes off no problem, but it seems to set stopped to true locally in titlescreen, and not in main. I can fix this by creating a class stopFlag and doing the exact same thing, except in the object.
My question is why do I need to make a new class to do this? Is there a way I can set a global flag in main which is just a boolean without making an object out of it? How can I have the callback reference that boolean?
Edit:
I declare stopped like this:
stopped = False
Here is the quit callback register call:
titleScreen.registerCallbackQuit(quit)
Which looks like:
def registerCallbackQuit(self, callback):
self.callbackQuit = callback
And it calls quit if it gets a in the user input.
global stopped would work (probably). People use classes to avoid globals (among other things). If 'stopped' is spread out over many files, you would need to import it.

Categories

Resources