Possible ways to change flag values inside a while loop in python? - python

So my problem is this: I'm running a while loop that will execute Function1 every time, Function2 and Function3 will only be executed when their respective flags are set to True, and I want to be able to alter those flags while the loop is running.
while brkFlag == False:
Function1.run()
if flag2 == True:
Function2.run()
else:
pass
if flag3 == True:
Function3.run()
else:
pass
if someConditions == True:
brkFlag = True
Currently I want to change those flags with a GUI while the loop is running and am trying to do this with tkinter's Buttons and Checkboxes, but no luck so far.
I also can't use multithreading or multiprocessing as they will considerably slow down the speed of the loop (which is already barely acceptable as it is right now, because there are lots of calculations in each function and I need to show the results in a real-time fashion).
Edit: So it seems that there is no way other than doing multithreading/processing after all.

A simple way is to pass a mutable container containing the flags, for example a list:
flags = [flag2, flag3, someConditions ]
while brkFlag == False:
Function1.run(flags)
if flags[0] == True:
Function2.run(flags)
else:
pass
if flags[1] == True:
Function3.run(flags)
else:
pass
if someConditions == True: # or if flags[2] == True:
brkFlag = True
In the callee you implement more or less:
...
def run(flags):
...
flags[0] = True # set flag2
...

Related

Increase just by one when a key is pressed

I want to increase the variable "shot_pressed" just by one when the key "s" is pressed no matter how long I pressed. But the result is that the variable keeps on increasing. The longer I pressed, the bigger the value of the variable. Below is a part of my code.
import keyboard
shot_pressed = 0
if keyboard.is_pressed('s'):
shot_pressed += 1
First of all looks like you use https://pypi.python.org/pypi/keyboard
Second, I assume your code is not like you wrote above but like
import keyboard
shot_pressed = 0
while True:
if keyboard.is_pressed('s'):
shot_pressed += 1
print("shot_pressed %d times"%shot_pressed)
If yes, here is the core of the problem: is_pressed will be always True, while key is pressed. So if condition will be True and while will repeat it many times.
There are two ways of dealing with that.
1) Use the same method, but check if this is the first is_pressed moment, so inroduce was_pressed variable:
import keyboard
shot_pressed = 0
was_pressed = False
while True:
if keyboard.is_pressed('s'):
if not was_pressed:
shot_pressed += 1
print("shot_pressed %d times"%shot_pressed)
was_pressed = True
else:
was_pressed = False
2) Better use the library. You can set a hook, so on key pressed your function will be called (only once for one press). So the code will look like this:
import keyboard
shot_pressed = 0
def on_press_reaction(event):
global shot_pressed
if event.name == 's':
shot_pressed += 1
print("shot_pressed %d times"%shot_pressed)
keyboard.on_press(on_press_reaction)
while True:
pass
I do not know that keyboard module but the problem with your code is that the program takes input once. Your program should wait next input from keyboard. Try to use while loop to take inputs from user.
import keyboard
import time
shot_pressed = 0
try:
while True:
if keyboard.is_pressed("S"):
shot_pressed += 1
time.sleep(0.1)
print(sh)
except Exception as er:
pass
Or can use read key
try:
shot_pressed = 0
while True:
key.read_key()
if key.is_pressed("s"):
sh += 1
print(shot_pressed)
except Exception as er:
pass
I haven't used that module, but you probably want the same thing that you would want in javascript. keyboard.KEY_DOWN instead of is_pressed.
https://github.com/boppreh/keyboard#keyboard.KEY_DOWN
You probably need to handle things asynchronously as well.

Command function for button "resets"

So in my tkinter python program I am calling on a command when a button is clicked. When that happens it runs a function but in the function I have it set a label to something on the first time the button is clicked and after that it should only update the said label. Basically after the attempt it changes the attempt to 1 ensuring the if statement will see that and not allow it to pass. However it keeps resetting and I don't know how to stop it. When you click the button no matter first or third the button resets and proof of that occurs because the h gets printed. It's as if the function restarts but it shouldn't since it's a loop for the GUI.
def fight(): #Sees which one is stronger if user is stronger he gets win if no he gets loss also displays enemy stats and removes used characters after round is finished
try:
attempt=0
namel = ""
namer=""
left = lbox.curselection()[0]
right = rbox.curselection()[0]
totalleft = 0
totalright = 0
if left == 0:
namel = "Rash"
totalleft = Rash.total
elif left==1:
namel = "Untss"
totalleft = Untss.total
elif left==2:
namel = "Illora"
totalleft = 60+35+80
if right == 0:
namer = "Zys"
totalright = Zys.total
elif right==1:
namer = "Eentha"
totalright = Eentha.total
elif right==2:
namer = "Dant"
totalright = Dant.total
lbox.delete(lbox.curselection()[0])
rbox.delete(rbox.curselection()[0])
print(namel)
print(namer)
if attempt == 0:
wins.set("Wins")
loss.set("Loss")
print("h")
attempt=1
if (totalleft>totalright):
wins.set(wins.get()+"\n"+namel)
loss.set(loss.get()+"\n"+namer)
else:
wins.set(wins.get()+"\n"+namer)
loss.set(loss.get()+"\n"+namel)
except IndexError:
pass
Also for those of you who saw my previous question I still need help with that I just also want to fix this bug too.
At beginning of function fight you set attempt = 0 so you reset it.
Besides attempt is local variable. It is created when you execute function fight and it is deleted when you leave function fight. You have to use global variable (or global IntVar)
attempt = 0
def fight():
global attempt
BTW: of you use only values 0/1 in attempt then you can use True/False.
attempt = False
def fight():
global attempt
...
if not attempt:
attempt = True

How to stop a function

For example:
def main():
if something == True:
player()
elif something_else == True:
computer()
def player():
# do something here
check_winner() # check something
computer() # let the computer do something
def check_winner():
check something
if someone wins:
end()
def computer():
# do something here
check_winner() # check something
player() # go back to player function
def end():
if condition:
# the player wants to play again:
main()
elif not condition:
# the player doesn't want to play again:
# stop the program
# whatever i do here won't matter because it will go back to player() or computer()
main() # start the program
My problem is that if a certain condition becomes true (in the function check_winner) and function end() executes it will go back to computer() or player() because there's no line that tells the computer to stop executing player() or computer(). How do you stop functions in Python?
A simple return statement will 'stop' or return the function; in precise terms, it 'returns' function execution to the point at which the function was called - the function is terminated without further action.
That means you could have a number of places throughout your function where it might return.
Like this:
def player():
# do something here
check_winner_variable = check_winner() # check something
if check_winner_variable == '1':
return
second_test_variable = second_test()
if second_test_variable == '1':
return
# let the computer do something
computer()
In this example, the line do_something_else() will not be executed if do_not_continue is True. Control will return, instead, to whichever function called some_function.
def some_function():
if do_not_continue:
return # implicitly, this is the same as saying `return None`
do_something_else()
This will end the function, and you can even customize the "Error" message:
import sys
def end():
if condition:
# the player wants to play again:
main()
elif not condition:
sys.exit("The player doesn't want to play again") #Right here
def player(game_over):
do something here
game_over = check_winner() #Here we tell check_winner to run and tell us what game_over should be, either true or false
if not game_over:
computer(game_over) #We are only going to do this if check_winner comes back as False
def check_winner():
check something
#here needs to be an if / then statement deciding if the game is over, return True if over, false if not
if score == 100:
return True
else:
return False
def computer(game_over):
do something here
game_over = check_winner() #Here we tell check_winner to run and tell us what game_over should be, either true or false
if not game_over:
player(game_over) #We are only going to do this if check_winner comes back as False
game_over = False #We need a variable to hold wether the game is over or not, we'll start it out being false.
player(game_over) #Start your loops, sending in the status of game_over
Above is a pretty simple example... I made up a statement for check_winner using score = 100 to denote the game being over.
You will want to use similar method of passing score into check_winner, using game_over = check_winner(score). Then you can create a score at the beginning of your program and pass it through to computer and player just like game_over is being handled.
Maybe you are looking yield, its same as return but it stops function's execution rather than terminating functions, You can look at generators here.

Function called without being told to

Newish to python, working on a text adventure, testing out the use of functions.
def cell1():
loop = 1
while loop == 1:
print("ONE")
cave1 = input()
if cave1 == ("end?"):
print("\nthis should end program")
loop = 0
break
elif cave1 == ("TWO"):
global testvar
testvar = 1
option1()
else:
print("INVALID")
def option1():
print("TWO")
loop = 1
while loop == 1:
print("test1 definition")
print (testvar)
test1 = input()
if test1 == ("ONE"):
print("you pick up the cheese")
loop = 0
cell1()
elif test1 == ("THREE"):
option2()
else:
print("INVALID")
def option2():
print("THREE")
loop = 1
while loop == 1:
print("This is option 3")
test2 = input()
if test2 == ("ONE"):
print("testering2")
cell1()
elif test2 == ("TWO"):
global testvar
testvar = 2014
option1()
else:
print("INVALID")
run = True
while run == (True):
print ("testing 123")
cell1()
print("restart about to activate")
cont = input("Restart? ")
if (cont) != "yes":
break
This program should allow you to go between options (what would be rooms) and eventually in cell1, the program should be end-able.
if the program is run and "end?" is typed as the first input, the program goes into the continue bit at the bottom, however, if you go between the 'rooms' then back to cell1, typing "end?" will call option 2.
Ive had a look around and it is still baffling me, am i ding something wrong?
Any help is appreciated, thank you.
The reason "end?" only quits for the player when they are within the first cell is because you're only checking for that input therein. The execution contained within option1() and option2() doesn't affect the execution of cell1(). You're not returning anything from your option functions, nor are you changing a sentinel value.
So, there's two basic ways you could go about this.
First, you could return a value from your functions:
if option1() == "END":
break
Or, you could alter your while loop:
# is_running is defined globally
while is_running:
And then just set is_running to False in any of your methods whenever the user types "end?". That'd probably be the easiest way with the design you're using now.
I'm sure you can tell, though, that in general your program is going to get exponentially more complex as you add more rooms and your function calls get further nested.
I'm pretty sure that the issue you're having is because you don't always break out of the loop in one function when you call another function. For instance, if your entries were TWO, ONE then end?, you'd find yourself still in the cell1 loop. That's because when the inner call to cell1 returns, the control flow of the program goes back to where that function was called from, which is option1, since loop is now 0, the loop ends and option1 returns, to the outer call to cell1, where the loop is still running.
Unless you want the game you're designing to have a tree structure, where you can return to where you came from with different semantics than moving to some other place, I'd suggest using a different architecture. Rather than each of your functions calling the next function when appropriate, return that function instead. Then you'd write a single top level loop that calls the function. Here's an example where the function to be called by the top level loop is saved in a variable named state:
def cell1():
print("In cell1!")
while True:
choice = input("pick 'ONE' or 'TWO' (or type 'quit' to exit):")
if choice == "ONE":
return option1
elif choice == "TWO":
return option2
elif choice == "quit":
return None
else:
print("I'm sorry, I didn't understand that.")
def option1(): # these other two functions are very basic in my example
print("In option1!") # but you can make them as complex as you want
return option2
def option2():
print("in option2!")
return cell1
def control_loop(initial_state=cell1):
state = initial_state
while state is not None:
state = state() # the next state is the return value of the previous state
The problem is you are getting deeper and deeper within nested functions. For example, changing
if test1 == ("ONE"):
print("you pick up the cheese")
loop = 0
cell1()
to
if test1 == ("ONE"):
print("you pick up the cheese")
loop = 0
break
will allow you to run your program, enter room two, go back to room one, and "end?" will work properly. This won't fix your issues completely though because there is a similar problem where when you go from two to three where if you simply changed
if test2 == ("ONE"):
print("testering2")
cell1()
to
if test2 == ("ONE"):
print("testering2")
break
it would break the current function and go back into option1() (if you run your program, go to room two, then to room three, then back to one) where "end?" doesn't do anything. Hopefully this gets you on the right track.

Pause and resume a running script in Python 3.42 in Windows

I'm new to Python and have been googling for a couple of days and read all I can find on this forum. Might be that I don't understand it all but I haven't found a solution to my problem yet. Ask for forgiveness already if there's an answer already to my problem, then I haven't understood it.
I want to make a Pause function for my program Tennismatch. The program will when it's being run print the score of a tennis match like this: "15-0, 15-15 etc ongoing till the match ends. It will print the score line by line.
I want the user to be able to pause after x number of balls, games, etc. So I don't know when the user wants to pause and after the user has paused I want the user to be able to resume the tennismatch where it was.
Have seen the time.sleep() but as I have understood it you must know when you want to pause to use this and it also ain't an indefinetie pause like I want. With input() it's the same.
Am going to make a GUI later on when the code is finished. Happy for anything that leads me to solving my problem.
I use Windows and Python 3.42 and run the program in Shell.
A piece of the code (haven't written it all yet, it's more of a general situation when something is being printed line after line for some time and want to be able do pause in the CIL:
#self.__points = [0,0]
def playGame(self):
if self.server == True: #self.server is either True or False when someone calls playGame()
server = self.player_1.get_win_serve() #self.player_1 = an object of a class Player():
else:
server = self.player_2.get_win_serve() #get_win_serve() method returns the probability to win his serv (1-0)
while (0 < self.__points[0] - self.__points[1] >= 2 or 0 < self.__points[1] - self.__points[0] >= 2) and (self.__points[1] >= 4 or self.__points[0] >= 4):
x = random.uniform(0,1)
if x > 0 and x < server:
self.__points[0] += 1
else:
self.__points[1] += 1
# print('The score, by calling a score() function that I haven't written yet')
For dealing with events in main loop you need to make a separated thread which capture input or any other event.
import sys
from sys import stdin
from time import sleep
from threading import Thread
from Queue import Queue, Empty
def do_something():
sleep(1)
print 42
def enqueue_output(queue):
while True:
# reading line from stdin and pushing to shared queue
input = stdin.readline()
print "got input ", input
queue.put(input)
queue = Queue()
t = Thread(target=enqueue_output, args=(queue,))
t.daemon = True
t.start()
pause = False
try:
while True:
try:
command = queue.get_nowait().strip()
print 'got from queue ', command
except Empty:
print "queue is empty"
command = None
if command:
if command == 'p':
pause = True
if command == 'u':
pause = False
if not pause:
print pause
do_something()
except KeyboardInterrupt:
sys.exit(0)
I came up with the following.
while True:
try:
## Keep doing something here
## your regular code
print '.',
except KeyboardInterrupt:
## write or call pause function which could be time.sleep()
print '\nPausing... (Hit ENTER to continue, type quit to exit.)'
try:
response = raw_input()
if response.lower() == 'quit':
break
print 'Quitting...'
except KeyboardInterrupt:
print 'Resuming...'
continue
The Event loop might as well be the code I wrote with.
I don't see any user input so I assume that x emulates it. To pause the game if x < 0.1 and to unpause(/resume) it if x > 0.9, you could:
while your_condition(self.__points):
x = random.random()
if x < 0.1: # pause
self.pause()
elif x > 0.9: # resume
self.resume()
if self.is_paused:
continue # do nothing else only wait for input (`x`)
# assume your_condition() has no side-effects
# here's what the resumed version does:
print("...")
# change self.__points, etc
where pause(), resume(), is_paused() methods could be implemented as:
def __init__(self):
self.is_paused = False
def pause(self):
self.is_paused = True
def resume(self):
self.is_paused = False
as you can see the implementation is very simple.

Categories