Program not stopping when I press "Stop" [duplicate] - python

This question already has answers here:
Short description of the scoping rules?
(9 answers)
Closed 2 years ago.
I have a very strange problem. When I press stop, the code does not stop. see:
import tkinter as tk
x=tk.Tk()
stops=False
def stop():
stops=True
print("STOPPED")
tk.Button(x,command=stop,text="Stop").pack()
while not stops:
print(stops)
x.update()
x.update_idletasks()
If I press stop, why does still it keep on printing?
the stops variable is not edited in the while loop, so why doesn't it stop?
I have also tried adding this to the end of the while loop:
if stops:
break
But it still does not stop. Why?

I think you need to globalise the variable "stops" to modify the variable.
def stop():
global stops
stops=True
print("STOPPED")

I am bit late but with complete explanation
Yes, using global keyword will solve this issue.
Why and How ?
Explanation:
Global variables are the one that are defined and declared outside a function and we need to use them inside a function
If you create a variable with the same name inside a function, this variable will be local, and can only be used inside the function. The global variable with the same name will remain as it was, global and with the original value.
Now if you want to update this global variable via function you need to use keyword global which will update the global variable(i.e, stops)
import tkinter as tk
x=tk.Tk()
stops=False
def stop():
global stops
stops=True
print("STOPPED")
tk.Button(x, command=stop, text="Stop").pack()
while not stops:
print(stops)
x.update()
x.update_idletasks()

Related

Only run function it is not already running

I need to make on auto clicker that, when the mouse is clicked once (using the 'mouse' module), presses another 5 times. However, I also need to make sure that only the clicks done by the user activate it. Currently (because I don't need an unstoppable mouse as I've already had), it only prints "clicking". This is what I have so far.
jack = 0
import keyboard
import mouse
import sys
from time import sleep
def spamClick(f, jeff):
if jeff <= 0:
jeff = jeff+1
for i in range(f):
#mouse.click()
print ("Clicking")
sleep(0.1)
jeff = 0
mouse.on_click(spamClick, args=(5, jack))
#keyboard.add_hotkey('ctrl+g', spamClick)
keyboard.add_hotkey('ctrl+#', mouse.unhook_all)
keyboard.add_hotkey('ctrl+#', sys.exit)
Thank you in advance.
An easy fix for this is having a top level variable keeping track of the state.
The issue is that you have a function that does an action that starts itself again.
It's functionally the same as
def examplecode():
print("Do stuff")
examplecode()
This is the same as an infinite loop, in your case even worse because you call the function multiple times every time (5 times per action).
So your options to prevent that are as follows:
Have two different ways of clicks, one that triggers the "onclick" event, and one that doesn't.
Use a helper function that keeps track of the "state" of your program. Instead of calling "spamClick()" as your onclick event add the following to your program:
A top level variable that is True when you want it to accept clicks: isUser=True
A function you call instead of "spamclick" that checks the state of the global Var and only then triggers the code:
def examplefunc(num,var):
if isUser:
isUser=False
spamClick(num,var)
isUser=True
I still don't get how your program just "clicks endlessly" instead of crashing due to hitting max recursion depth, but this should work (while being very hacky)
Edit: You should use better naming for variables instead of "jeff", it will make your life worse if you don't down the line. For example "isUser" indicates that it's a boolean (because "isWhatever" indicates it holds a state as a boolean) and states if the input is by a user. Alternatively you could use isFunctionRunning=False that states if the function is on. You would have to switch all the True and False assignments in my example of course to still make sense.

can't print variable from previous function in python [duplicate]

This question already has answers here:
Cannot call a variable from another function
(4 answers)
Closed 2 years ago.
I have got a database program to keep data in, and I can't solve this problem:
I have got two functions. When you input A into the program
the function called addy() starts
and ask for more input into a variable
then it returns to the main screen,
then the user can Input S
which starts Show()
and then it's supposed to show what you have added into the variable
PROBLEM:
It's not getting the value from the previous definition.
CODE:
def addy():
os.system('cls')
addel = input('what is the name of the operating system?: \n')
os.system('cls')
time.sleep(1)
print(addel + ' Has been added to the database!')
time.sleep(2)
program()
def show():
print('Heres a list of the operating systems you have added:')
time.sleep(5)
program()
addel = addy()
print(addel) # this should print the value from the previous function
The are 2 reasons why
Addel is a local variable not a global one. Therefore, you can only use it in your addy function.
Say your intent was not to use it which is what it seems, you wrote
addel = addy()
the function addy has no return value so your code wont work.
to fix this write
return addel
as the last line in your addy function then it will work because now the function has a return value.

Why is my guess variable Global? [duplicate]

This question already has answers here:
Short description of the scoping rules?
(9 answers)
Closed 4 years ago.
Mac OS 10.13.16
Python 3.7
PyCharm
I was going through a tutorial for this guessing game and I came across something I thought was weird. On line 18 I call on the guess variable, which I though was a Local Variable under the for loop created above it, let's me call on it as if it were a Global. I though if a var is declared within a function or loop it makes it a local. Can someone help explain this to me.
import random
print("Hello what is your name?")
name = input()
print("Well " + name + " I am thinking of a number between 1 and 20")
secretNumber = random.randint(1,20)
for guessesTaken in range(1, 7):
print("Take a guess.")
guess = int(input())
if guess < secretNumber:
print("Sorry to low")
elif guess > secretNumber:
print("Sorry to high")
else:
break
if guess == secretNumber:
print("Great job " + name + ". You guessed my number in " + str(guessesTaken) + " moves.")
else:
print("Sorry the number I was thinking of is " + str(secretNumber))
Taken from another answer: It appears to be a design decision in the python language. Functions still have local variables, but for loops don't create local variables.
Previous proposals to make for-loop variables local to the loop have stumbled on the problem of existing code that relies on the loop variable keeping its value after exiting the loop, and it seems that this is regarded as a desirable feature.
http://mail.python.org/pipermail/python-ideas/2008-October/002109.html
Excerpt from Python's documentation:
A block is a piece of Python program text that is executed as a unit.
The following are blocks: a module, a function body, and a class
definition. Each command typed interactively is a block. A script file
(a file given as standard input to the interpreter or specified as a
command line argument to the interpreter) is a code block. A script
command (a command specified on the interpreter command line with the
‘-c’ option) is a code block. The string argument passed to the
built-in functions eval() and exec() is a code block.
And:
A scope defines the visibility of a name within a block. If a local
variable is defined in a block, its scope includes that block. If the
definition occurs in a function block, the scope extends to any blocks
contained within the defining one, unless a contained block introduces
a different binding for the name.
When a name is used in a code block, it is resolved using the nearest
enclosing scope. The set of all such scopes visible to a code block is
called the block’s environment.
Local variables are visible anywhere in the same code block. A for loop is not a code block by definition, however, and therefore the local variable defined in your for loop is still visible after the loop, within the same module.

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 :)

Function not changing global variable

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

Categories

Resources