Reputation: 583
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.
Upvotes: 3
Views: 611
Reputation: 140168
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).
Upvotes: 4