If I want to call a function both in a single iteration and in a looping function, that reuses the same code, whats the proper way to create the two functions?
Here is an example single function DoStuff and 3 attempts to create a second way of calling it, in __name__=="__main__".
import time
def DoStuff(txt):
"""Do it one time"""
print(txt)
def LoopStuff(txt):
"""Function of a Function"""
try:
while True:
if time.time() % 5 < 1:
DoStuff(txt)
time.sleep(1)
except KeyboardInterrupt:
print("You killed it.")
except:
print("Loop Failed.")
def Loop(function):
"""This one's broken"""
try:
while True:
if time.time() % 5 < 1:
function()
time.sleep(1)
except KeyboardInterrupt:
print("You killed it.")
except:
print("Loop Failed.")
def Looped(function):
"""Wrapper"""
def wrap(*args,**kwargs):
try:
while True:
if time.time() % 5 < 1:
function(*args, **kwargs)
time.sleep(1)
except KeyboardInterrupt:
print("You killed it.")
except:
print("Loop Failed.")
return wrap
#Looped
def WrapStuff(txt):
"""Hows this work?"""
DoStuff(txt)
if __name__ == '__main__':
DoStuff("one time text")
LoopStuff("Function fuction")
Loop(DoStuff("what's your"))
WrapStuff("conjunction?")
I was trying to create a loop that ran every min, regardless of execution time, but I have shortened it to 5 seconds here for troubleshooting. Maybe there's a better way to do this with a chron type behavior, but that's not really the question I'm asking here.
The 1st and 3rd attempt work but the 2nd exits with
in <module> Loop(DoStuff("what's your"))
in Loop function()
TypeError: 'NoneType' is not callable
I just went trial and error until I found this code that worked. It seems like this will let me use Looped in a wrapper function and in this single line style. If you have a better answer, please share.
It's just a cleaner way of what I was trying to accomplish with WrapSuff.
ShortWrap = Looped(DoStuff)
ShortWrap('my text')
I can see, in hindsight, that the second example Loop(DoStuff("what's your")) is just a failed half-step between the first and third example.
Related
I'm getting the following error when I run my code:
I'm guessing the root of this error is when I execute the fetch_ticker() function.
I have two python scripts: main.py and functions.py (includes all the functions)
I've read somewhere else that strategically adding a time.sleep(0.01) can solve the issue.
Would it be wise to add time.sleep(0.01) before any line that requests something through BinanceUS API?
For example,
if now.hour == 0 and now.minute == 0 and (0 <= now.second < 10):
time.sleep(0.01)
target = calc_target(binanceUS, symbol)
time.sleep(0.01)
balance = binanceUS.fetch_balance()
time.sleep(0.01)
usd = balance['total']['USD']
op_mode = True
time.sleep(10)
Though I'm not sure if this will solve the issue...or I also thought about creating an error-handling code for all the functions that I use, but I'm not sure how I would go about it when the function includes one or more if-statements. For example,
def enter_position(exchange, symbol, cur_price, target, amount, position):
try_cnt = 3
while try_cnt > 0:
if cur_price > target:
try:
position['type'] = 'long'
position['amount'] = amount
exchange.create_market_buy_order(symbol=symbol, amount=amount)
except Exception as e:
print("Connection error, trying again...")
try_cnt -= 1
time.sleep(1)
else:
exchange.create_market_buy_order(symbol=symbol, amount=amount)
Not sure if this will work, though.
I'm very confused about how to go around this error. In fact, I'm not even sure what the error means. Would any of the two solutions look plausible?
I have three functions that "trickle down" and get called within another like so:
async def start_swings(self, server, user):
try:
while self.jailed[server.id][user.id]['current'] != 0:
await self.get_question(server, user)
else:
await self.escape_jail(server, user)
except KeyError: # User isn't jailed
pass
async def get_question(self, server, user):
rnd = random.choice(range(2))
if rnd == 0:
await self.swing_math(server, user)
elif rnd == 1:
await self.swing_reverse(server, user)
async def swing_math(self, server, user):
num1 = random.randint(1, 1000)
num2 = random.randint(1, 1000)
ops = ['+', '-']
op = random.choice(ops)
ans = int(eval(str(num1) + op + str(num2)))
await self.bot.send_message(user, "**\N{HAMMER} It's going to take you `{}` more swings to break free.**\n```What is {} {} {}?```\n*I might doze off if you take too long to answer. If you don't get a reply from me within a few seconds, type `>swing`. If you try to use `>swing` as a way to reset your current question, you'll get a cooldown penalty.*".format(self.jailed[server.id][user.id]['current'], num1, op, num2))
resp = await self.bot.wait_for_message(author=user)
resp = resp.clean_content
if resp == str(ans):
await self.bot.send_message(user, "Correct. \N{WHITE HEAVY CHECK MARK} Take a swing.")
self.jailed[server.id][user.id]['current'] -= 1
dataIO.save_json('data/jail/jailed.json', self.jailed)
elif resp == ">swing":
return
else:
await self.bot.send_message(user, "Wrong. \N{CROSS MARK} Let me put that brick back in place.")
self.jailed[server.id][user.id]['current'] += 1
dataIO.save_json('data/jail/jailed.json', self.jailed)
In the third function, you'll see this statement:
elif resp == ">swing":
return
How can I get that to effectively "double return" so that it instead returns to start_swings instead of get_questions? I am fairly new to Python and don't know exactly what to call this. I'm effectively trying to get execution of this script to stop completely at this area of the code:
elif resp == ">swing":
return
… rather than just having it return to the last function called.
You cannot "pop" the stack manually like you could do in old times basic, but you can use an exception (even if it's considered bad practice if the exception isn't thrown "exceptionnally"):
Inherit from Exception:
class DoubleReturnException(Exception):
pass
Install the handler:
while self.jailed[server.id][user.id]['current'] != 0:
try:
await self.get_question(server, user)
except DoubleReturnException:
pass
else:
Then instead of returning, just:
raise DoubleReturnException
to return to the except part of the handler (whatever the number of calls are).
Defining your own exception is necessary because it ensures that the program returns for this reason, and not for a ValueError or any other exception that the program could throw.
That must remain an exceptional case. Programming by throwing exceptions everywhere lead to "spaghetti code" and somehow reinstates the evil goto statement. You may find that interesting in the last stages of a stable product, when you cannot break all the (flawed) design for a particular case (but personally I never had to use tricks like that).
Is is possible to stop a thread prematurely when it is stuck inside a while loop? Below is my sample code, which runs correctly, since each time it calls loop_thread it will check to see if the threading.Event() flag is set. When attempting to run the code for a file that processes information much longer than each second, there is no way to stop the entire function from continuing its execution until the next iteration. For example, if I run dld_img_thread, it takes about 5 minutes to complete its execution and recheck the while loop to see if should proceed. What I want to have happen is kill the dld_img_thread at a time shorter than 5 minutes (e.g. 1 minute). I don't care if the data is lost, just that the thread stops before the function finishes execution. Thank you
import threading, time, pythoncom, read_mt0
import powerfail_debugport_reader as pf_dbg_rdr
import powerfail_firmware_downloader as pf_fwdld
def loop_thread(thread_name, thread_event):
loopCnt = 0
print "\nstarting {}".format(thread_name)
print "is {0} alive? {1}\n".format(thread_name, L00P_thread.is_alive())
while not thread_event.is_set():
print("value of loopCnt = {}".format(loopCnt))
loopCnt += 1
time.sleep(1)
print('stopping {}\n'.format(thread_name))
def image_dld(thread_name, thread_event):
pythoncom.CoInitializeEx(pythoncom.COINIT_MULTITHREADED)
print "\nstarting {}".format(thread_name)
print "is {0} alive? {1}\n".format(thread_name, dld_img_thread.is_alive())
while not thread_event.is_set():
pf_fwdld.power_fail_test()
print('stopping {}'.format(thread_name))
def debug_port_thread(thread_name, thread_event):
pythoncom.CoInitializeEx(pythoncom.COINIT_MULTITHREADED)
print "\nstarting {}".format(thread_name)
print "is {0} alive? {1}\n".format(thread_name, debug_thread.is_alive())
pf_dbg_rdr.debug_port_reader()
print('\nstopping {}'.format(thread_name))
def main():
global L00P_thread, debug_thread
pf_dbg_rdr.samurai_event = threading.Event()
L00P_thread = threading.Thread(target=loop_thread, \
args=('L00P_thread', pf_dbg_rdr.samurai_event))
dld_img_thread = threading.Thread(target=image_dld, \
args=('image_download', pf_dbg_rdr.samurai_event))
debug_thread = threading.Thread(target=debug_port_thread, \
args=('debug_port_reader', pf_dbg_rdr.samurai_event))
L00P_thread.start()
dld_img_thread.start()
debug_thread.start()
debug_thread.join()
if __name__ == '__main__':
main()
print('processes stopped')
print "Exiting Main Thread"
Use a second variable in your while condition that you can change once your timeout is reached.
For example:
shouldRun = True
while not thread_event.is_set() and shouldRun:
print("value of loopCnt = {}".format(loopCnt))
loopCnt += 1
time.sleep(1)
if loopCnt > 60: shouldRun = False
would stop after 60 iterations (about 60 seconds given you sleep for 1 second on each iteration).
noprob=["nothing","none","no damage"]
while True:
q1=input("input your answer:")
answer=q1.split(' ')`
if any(a in answer for a in noprob):
function()#wont call this
break
else:
print("else statement")
continue
def function():
print("code now works")
my code won't call the function when it should. this code should recognize user input and output necessary actions.
new whole code: with added elif statement which i think is the problem with the code
`noprob=["nothing","none","no damage"]
something=["something","yes"]`
def function():
print("code now works")`
def something():
print("something, code works")
while True:
q1=input("input your answer:")
answer=q1.split(' ')`
if any(a in answer for a in noprob):
function()#wont call this
break
elif any(a in answer for a in something):
something()
break
else:
print("else statement")
continue
Python executes code form top to bottom. So you won't get to execute function if you don't declare its definition before. move the function before the while loop.
noprob=["nothing","none","no damage"]
def function():
print("code now works")
while True:
q1=input("input your answer:")
answer=q1.split(' ')
if any(a in answer for a in noprob):
function()#wont call this
break
else:
print("else statement")
continue
Your problem is, your list and function both named something. Rename one and change your code accordingly.
something=["something","yes"]
def something(): #this one shadows your list and needs to be renamed
print("something, code works")
For generator thingy, Python 3.5
I tried:
from time import sleep
while sleep(3):
input("Press enter to continue.")
But it doesn't seem to work. I want the program to await user input, but if there's no user input after 10 minutes, continue with the program anyway.
This is with python 3.
Why does the code not work?
time.sleep returns nothing; the value of the time.sleep(..) become None; while loop body is not executed.
How to solve it
If you're on Unix, you can use select.select.
import select
import sys
print('Press enter to continue.', end='', flush=True)
r, w, x = select.select([sys.stdin], [], [], 600)
Otherwise, you should use thread.
Windows specific solution that use msvcrt:
import msvcrt
import time
t0 = time.time()
while time.time() - t0 < 600:
if msvcrt.kbhit():
if msvcrt.getch() == '\r': # not '\n'
break
time.sleep(0.1)
Here is a simple way using an alarm. When the time expires, the lambda function is called, which would raise a ZeroDivisionError.
from signal import signal, alarm, SIGALRM
signal(SIGALRM, lambda x, y: 1/0)
try:
alarm(600)
input("Press enter to continue.")
except ZeroDivisionError:
print("timed out")
Another way to do it is this:
from time import sleep
print("I'm executing")
try:
print("Wake up Ctrl-C!")
sleep(600)
except KeyboardInterrupt:
print("I woke up!")
else:
print("I'm executing again.")
Not the greatest of answers and it definitely feels like an abuse of exceptions, but it works.