I'm trying to make a program that is effectively an alarm clock. It's more complicated than it might seem that it needs to be, but there are reasons for that, that I won't go into here. The issue I'm having, though, is that I create an Alarm object inside a nested function, but whatever I do, I can't get that object to be accessed outside of that function... I've attached the abridged code below. Any of the calls to "check" or "set" etc. outside of setAlarm can never find the "alarm" variable. Please let me know what I'm doing wrong — I tried declaring the variable as global, as you'll see, but it still doesn't work out...
Thanks!
class Alarm(threading.Thread):
def __init__(self, datetime, grace, close):
super(Alarm, self).__init__()
self.datetime = datetime
self.grace = grace
self.close = close
self.keep_running = True
def run(self):
try:
while self.keep_running:
now = datetime.datetime.now()
if now > self.datetime + datetime.timedelta(minutes=self.grace):
print "Oh no! It's %02d:%02d, which is %d minutes past your alarm time of %02d:%02d!" % (now.hour,now.minute,self.grace,self.datetime.hour,self.datetime.minute)
print "ALARM NOW!\a\a\a\a\a\a\a\a\a\a"
break
time.sleep(10)
except:
return
def just_die(self):
self.keep_running = False
def setAlarm():
print "What time would you like to set the alarm for? (in 00:00 military time please)"
wakeup = raw_input()
wakeuphour = int(wakeup[:2])
wakeupmin = int(wakeup[3:])
now = datetime.datetime.now()
if now.hour > wakeuphour or (now.hour == wakeuphour and now.minute > wakeupmin):
alarmday = now + datetime.timedelta(days=1)
alarmtime = datetime.datetime(alarmday.year,alarmday.month,alarmday.day,wakeuphour,wakeupmin)
else:
alarmtime = datetime.datetime(now.year,now.month,now.day,wakeuphour,wakeupmin)
close = 15
grace = 5
alarm = Alarm(alarmtime, grace, close)
if alarmtime.day != now.day:
print "Your alarm is set for %02d:%02d tomorrow." % (alarmtime.hour,alarmtime.minute)
else:
print "Your alarm is set for %02d:%02d today." % (alarmtime.hour, alarmtime.minute)
def runAlarm():
setAlarm()
alarm.start()
while True:
print "You can say 'stop', 'check', 'change', 'set', or 'quit'"
text = str(raw_input())
if text == "stop":
if alarm != 0:
alarm.just_die()
alarm = 0
print "Okay, I've cancelled the alarm."
else:
print "There was no alarm to stop..."
elif text == "check":
if alarm == 0:
print "Sorry, you don't have any alarm set. To create an alarm, type 'set'"
else:
pass
elif text == "change":
pass
elif text == "set":
alarm = 0
setAlarm()
alarm.start()
elif text == "quit":
print "Sure thing. Bye bye!"
break
else:
print "Sorry, I didn't understand that. Please try again."
You've created alarm as a local variable. Variables defined in a function are local by default, and local means exactly what it sounds like—it only exists inside that function.
You could fix this by explicitly making it a global variable. That's not a great idea, but it's the smallest change. Just add the statement global alarm to the top of both setAlarm and every function that wants to access it.
A better solution is to return alarm from setAlarm. Then, in the code that calls it, just store the return value. For example:
def setAlarm():
# your existing code
return alarm
def runAlarm():
alarm = setAlarm()
# your existing code
Now, runAlarm has its own local reference to the same object, also named alarm, so it can use that.
Related
is there any way for ask question by if statement and after afew sec if user didnot give any answer , if state use a default answer?
inp = input("change music(1) or close the app(2)")
if inp = '1':
print("Music changed)
elif inp = '2':
print("good by")
in this case if user dont give any answer after 30 sec by default if statement choose number 3
from threading import Timer
out_of_time = False
def time_ran_out():
print ('You didn\'t answer in time') # Default answer
out_of_time = True
seconds = 5 # waiting time in seconds
t = Timer(seconds,time_ran_out)
t.start()
inp = input("change music(1) or close the app(2):\n")
if inp != None and not out_of_time:
if inp == '1':
print("Music changed")
elif inp == '2':
print("good by")
else:
print ("Wrong input")
t.cancel()
Timer Objects
This class represents an action that should be run only after a certain amount of time has passed — a timer. Timer is a
subclass of Thread and as such also functions as an example of
creating custom threads.
Timers are started, as with threads, by calling their start() method.
The timer can be stopped (before its action has begun) by calling the
cancel() method. The interval the timer will wait before executing its
action may not be exactly the same as the interval specified by the
user.
For example:
def hello():
print("hello, world")
t = Timer(30.0, hello)
t.start() # after 30 seconds, "hello, world" will be printed
class threading.Timer(interval, function, args=None, kwargs=None)
Create a timer that will run function with arguments args and keyword
arguments kwargs, after interval seconds have passed. If args is None
(the default) then an empty list will be used. If kwargs is None (the
default) then an empty dict will be used.
cancel()
Stop the timer, and cancel the execution of the timer’s action. This will only work if the timer is still in its waiting
stage.
Here's an alternative way to do it (python 3), using multiprocessing. Note, to get the stdin to work in the child process, you have to re open it first. I'm also converting the input from string to int to use with the multiprocessing value, so you might want to error check there as well.
import multiprocessing as mp
import time
import sys
import os
TIMEOUT = 10
DEFAULT = 3
def get_input(resp: mp.Value, fn):
sys.stdin = os.fdopen(fn)
v = input('change music(1) or close the app (2)')
try:
resp.value = int(v)
except ValueError:
pass # bad input, maybe print error message, try again in loop.
# could also use another mp.Value to signal main to restart the timer
if __name__ == '__main__':
now = time.time()
end = now + TIMEOUT
inp = 0
resp = mp.Value('i', 0)
fn = sys.stdin.fileno()
p = mp.Process(name='Get Input', target=get_input, args=(resp, fn))
p.start()
while True:
t = end - time.time()
print('Checking for timeout: Time = {:.2f}, Resp = {}'.format(t, resp.value))
if t <= 0:
print('Timeout occurred')
p.terminate()
inp = DEFAULT
break
elif resp.value > 0:
print('Response received:', resp.value)
inp = resp.value
break
else:
time.sleep(1)
print()
if inp == 1:
print('Music Changed')
elif inp == 2:
print('Good Bye')
else:
print('Other value:', inp)
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
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.
I'm learning Python via book and internet. I'm trying to keep score of a game in a separate class. In order to test my idea, i've constructed a simple example. It looks too complicated for some reason. Is there a simpler/better/more Pythonic way to do this?
My code is as follows:
import os
class FOO():
def __init__(self):
pass
def account(self, begin, change):
end = float(begin) + float(change)
return (change, end)
class GAME():
def __init_(self):
pass
def play(self, end, game_start):
os.system("clear")
self.foo = FOO()
print "What is the delta?"
change = raw_input('> ')
if game_start == 0:
print "What is the start?"
begin = raw_input('> ')
else:
begin = end
change, end = self.foo.account(begin, change)
print "change = %r" % change
print "end = %r" % end
print "Hit enter to continue."
raw_input('> ')
self.play_again(end, game_start)
def play_again(self, end, game_start):
print "Would you like to play again?"
a = raw_input('> ')
if a == 'yes':
game_start = 1
self.play(end, game_start)
else:
print "no"
exit(0)
game = GAME()
game.play(0, 0)
Here's how I would format your code:
import os
class Game(object):
def play(self, end, game_start=None):
os.system("clear")
change = input('What is the delta? ')
# Shorthand for begin = game_start if game_start else end
begin = game_start or end
end = float(begin + change)
print "change = {}".format(change)
print "end = {}".format(end)
self.play_again(end, game_start)
def play_again(self, end, game_start):
raw_input('Hit enter to continue.')
if raw_input('Would you like to play again? ').lower() in ['yes', 'y']:
self.play(end, game_start)
else:
exit(0)
if __name__ == '__main__':
game = Game()
game.play(0, 0)
And a few tips:
I wouldn't create a new class that contains only code to perform one specific task. If the class doesn't take arguments or doesn't simplify your code, don't create it. Your Game class is an exception, however, as you would probably add more code to it.
In Python, classes are written in CamelCase. Global constants are usually written in UPPERCASE.
raw_input() returns a string. input() returns the string evaluated into a Python object.
I asked the question a better way and got what I was looking for here:
python: how do I call a function without changing an argument?
I'm trying to make a text-based game in Python, however, code could get out of hand pretty quickly if I can't do one thing on one line.
First, the source code:
from sys import exit
prompt = "> "
inventory = []
def menu():
while True:
print "Enter \"start game\" to start playing."
print "Enter \"password\" to skip to the level you want."
print "Enter \"exit\" to exit the game."
choice = raw_input(prompt)
if choice == "start game":
shell()
elif choice == "password":
password()
elif choice == "exit":
exit(0)
else:
print "Input invalid. Try again."
def password():
print "Enter a password."
password = raw_input(prompt)
if password == "go back":
print "Going to menu..."
else:
print "Wrong password. You are trying to cheat by (pointlessly) guess passwords."
dead("cheating")
def shell(location="default", item ="nothing"):
if location == "default" and item == "nothing":
print "Starting game..."
# starter_room (disabled until room is actually made)
elif location != "default" and item != "nothing":
print "You picked up %s." % item
inventory.append(item)
location()
elif location != "default" and item == "nothing":
print "You enter the room."
location()
else:
print "Error: Closing game."
def location():
print "Nothing to see here."
# Placeholder location so the script won't spout errors.
def dead(reason):
print "You died of %s." % reason
exit(0)
print "Welcome."
menu()
First, an explanation on how my game basically works.
The game has a 'shell' (where input is done) which receives information from and sends information to the different 'rooms' in the game, and it stores the inventory. It can receive two arguments, the location and an eventual item to be added to the inventory. However, line 40-42 (the first elif block in 'shell') and line 43-45 (the last elif block in 'shell') are supposed to go back to whatever location the location was (line 42 and 45, to be exact). I've tried "%s() % location" but that doesn't work, it seems to only work when printing things or something.
Is there any way to do this? If not, even writing an engine for this game would be a nightmare. Or I'd have to make an entirely different engine, which I think would be a way better approach in such a case.
Sorry if I made any mistakes, first question/post ever.
elif location != "default" and item != "nothing":
print "You picked up %s." % item
inventory.append(item)
location()
elif location != "default" and item == "nothing":
print "You enter the room."
location()
I guess you want to call a function having its name. For that you need a reference to the module or class inside which it was defined:
module = some_module # where the function is defined
function = getattr(module, location) # get the reference to the function
function() # call the function
If the function is defined in the current module:
function = globals()[location]
function() # call the function
If I correctly understand what you want is something like this : player will enter a location name and you want to call the related method. "%s"()%location will not work, a string (that is what is "%s" is not callable).
Let's try an OOP way :
class Maze:
def __init__(self):
# do what you need to initialize your maze
def bathroom(self):
#go to the bathroom
def kitchen(self):
# go to the kitchen
def shell(self, location="", item=""):
if location == "" and item == "":
print "Starting game..."
# starter_room (disabled until room is actually made)
elif location and item:
print "You picked up %s." % item
inventory.append(item)
getattr(self, location)()
elif location and item == "":
print "You enter the room."
getattr(self, location)()
else:
print "Error: Closing game."
maze = Maze()
while True: # or whatever you want as stop condition
location = raw_input("enter your location :")
item = raw_input("enter your location :")
maze.shell(location=location, item=item)
I think you can use the getattr() method.
Example : You want to call method "helloword()" from module "test", you would then do :
methodYouWantToCall = getattr(test, "helloworld")
caller = methodYouWantToCall()
Hope it gives you a clue.