I am currently trying to parse an HTML page. While doing so, I have to perform
Search a specific string and do some steps. (if this operation fails, go to step b)
Search a specific string using a different code and do some steps. (if this operation fails, go to step 3)
Search a specific string using a different code and do some steps.
I am doing like this and my question is if I have to try multiple times, how to specify try and except.
try:
#step 1
except: # ( not sure what kind of error will execute step2)
#step 2
except:
#step 3
thanks
The structure would be
try:
step 1
except:
try:
step 2
except:
step 3
Two notes:
First, although using exceptions is a very "pythonic" way to accomplish tasks, you should check, if you couldn't use a nested if/elif/else structure.
Second, there is a HTML Parser right in the Python standard library. This question also has some HTML to DOM Parsers in the answers (i.e. Parsers that construct a DOM structure out of the HTML document, if that makes your task easier). You should be very sure that you don't want to use an existing solution before writing your own :) ...
I agree with BlackVegetable that this could probably be done with a simple if/elif, but if you have a specific reason to want to use exceptions, you can do something like this:
for method in (method1, method2, method3):
try:
return method(parameter)
except VerySpecificException as _:
pass
as a more complete example:
def method1(param):
raise Exception('Exception: method 1 broke')
def method2(param):
raise Exception('Exception: method 2 broke')
def method3(param):
print param
def main():
param = 'success!'
for method in (method1, method2, method3):
try:
return method(param)
except Exception as e:
print e
if __name__ == '__main__':
main()
prints:
Exception: method 1 broke
Exception: method 2 broke
success!
If either of the first methods does not break, then those methods will return success and the loop will end.
This seems like it might be best served by using if/elif:
if conditionA:
# do something
elif conditionB:
# do something else
elif conditionC:
# do something completely different
else:
# go cry in a room
Related
for i in range(1,1000):
try:
x = some_crazy_function(my_parm(i))
if x in massive:
raise Exception()
massive.append(x)
x = dict(qnother_crazy_functionsl(x.replace('X','Y')))
x = new_func(x['constant'])[0]
next.append(x)
except:
break
I'm fairly new to python and I ran cross this fragment while maintaining someone else's code
To me that looks like a horrible way to exit a loop.
Is it the accepted way to code in python and I'll get used to it or is it as bad as it looks?
In the simplest of cases, a break would be the best (and simplest) way to break out of a loop:
if x in massive:
break
However, if throwing and catching an exception is more apt for your use case, I would recommend first defining your own user defined Exception class:
class MassiveException(Exception):
pass
Next, you can throw it like this:
if x in massive:
raise MassiveException()
And consequently catch it like this:
except MassiveException:
... # do something here
This is better because it makes your intent clear, and also gets rid of the catch-all except which will swallow other exceptions you really don't want swallowed.
I want to write decorator for generators that will catch all exceptions inside for loop, process them and continues loop.
I wrote this decorator (for Django 1.5 ORM):
def savepoint_loop(generator, uniq_error_in='_uniq'):
with commit_on_success():
sp = savepoint()
for obj in generator:
try:
yield obj
except DatabaseError as e:
if uniq_error_in not in e.args[0]:
raise
savepoint_rollback(sp)
yield None
else:
savepoint_commit(sp)
sp = savepoint()
And I use it like:
loop = savepoint_loop(offer.booking_data.iteritems())
for provider_name, booking_data in loop:
try:
BookingData.objects.create(
offer=pnr_offer, provider=provider_name, **booking_data)
except Exception as e:
loop.throw(e)
But it doesn't looks Pythonic. It allows me to make my code DRY, but looks confusing.
Is there any way to make it cleaner? At least I want to remove try-except-throw construction or change it to with operator.
Ideally it should look like this:
for provider_name, booking_data in savepoint_loop(
offer.booking_data.iteritems()):
BookingData.objects.create(
offer=pnr_offer, provider=provider_name, **booking_data)
import contextlib
#contextlib.contextmanager
def error_processor(uniq_error_in='_uniq'):
sp = savepoint()
try:
yield
except DatabaseError as e:
if uniq_error_in not in e.args[0]:
raise
savepoint_rollback(sp)
else:
savepoint_commit(sp)
This is a context manager that should do the job your coroutine does, but hopefully in a more understandable manner. You'd use it as follows:
with commit_on_success():
for provider_name, booking_data in offer.booking_data.iteritems():
with error_processor():
BookingData.objects.create(
offer=pnr_offer, provider=provider_name, **booking_data)
I couldn't fit the commit_on_success into the context manager, as the commit_on_success needs to go around the for loop, but the error handling needs to go inside the loop.
Hm... I think I see why this isn't straightforward. Any loop over an iterable basically comprises the following steps:
initialization
check termination condition
get next element
execute body of loop
... repeat steps 2-4 until the termination condition is satisfied
In a Python for loop, steps 2 and 3 are encapsulated in the for x in y statement. But it sounds like you want to use the same try...except to catch exceptions in steps 3 and 4. So it would appear that this will require you to "decompose" the for statement, i.e. implement it manually using a while loop instead.
iterable = offer.booking_data.iteritems() # step 2
try:
while True:
try:
provider_name, booking_data = iterable.next() # step 3
BookingData.objects.create(...) # step 4
except:
except StopIteration:
pass
I'm sure you would agree that this is stylistically worse than the code sample you already have in your question, with try...except inside the for loop. Sure, it's conceivable that it might be useful, if you really need steps 3 and 4 to be inside the same try block, but I would imagine cases like that are rare.
It's also possible there is some sneaky way to construct a generator that does what you want, but I can't think of one.
I am learning Python and have stumbled upon a concept I can't readily digest: the optional else block within the try construct.
According to the documentation:
The try ... except statement has an optional else clause, which, when
present, must follow all except clauses. It is useful for code that
must be executed if the try clause does not raise an exception.
What I am confused about is why have the code that must be executed if the try clause does not raise an exception within the try construct -- why not simply have it follow the try/except at the same indentation level? I think it would simplify the options for exception handling. Or another way to ask would be what the code that is in the else block would do that would not be done if it were simply following the try statement, independent of it. Maybe I am missing something, do enlighten me.
This question is somewhat similar to this one but I could not find there what I am looking for.
The else block is only executed if the code in the try doesn't raise an exception; if you put the code outside of the else block, it'd happen regardless of exceptions. Also, it happens before the finally, which is generally important.
This is generally useful when you have a brief setup or verification section that may error, followed by a block where you use the resources you set up in which you don't want to hide errors. You can't put the code in the try because errors may go to except clauses when you want them to propagate. You can't put it outside of the construct, because the resources definitely aren't available there, either because setup failed or because the finally tore everything down. Thus, you have an else block.
One use case can be to prevent users from defining a flag variable to check whether any exception was raised or not(as we do in for-else loop).
A simple example:
lis = range(100)
ind = 50
try:
lis[ind]
except:
pass
else:
#Run this statement only if the exception was not raised
print "The index was okay:",ind
ind = 101
try:
lis[ind]
except:
pass
print "The index was okay:",ind # this gets executes regardless of the exception
# This one is similar to the first example, but a `flag` variable
# is required to check whether the exception was raised or not.
ind = 10
try:
print lis[ind]
flag = True
except:
pass
if flag:
print "The index was okay:",ind
Output:
The index was okay: 50
The index was okay: 101
The index was okay: 10
I have been struggling with this error for a while now and there seems to be different opinions regarding why the interpreter complains about the 'continue'. So I would like to provide the erroneous code below.
import tweepy
import time
def writeHandlesToFile():
file = open("dataFile.txt","w")
try:
list = tweepy.Cursor(tweepy.api.followers,screen_name='someHandle',).items(100000)
print "cursor executed"
for item in list:
file.write(item.screen_name+"\n")
except tweepy.error.TweepError as e:
print "In the except method"
print e
time.sleep(3600)
continue
The reason I am particular on including the continue at the end is because I would like for the program to restart execution at the top from where it left off after the sleep in order to preserve the program state. I need the sleep in order to abide by the twitter api rate limits wherein the api only allows you to make a certain number of requests every hour.
So anyone who might see my mistake naive or otherwise please do point it out or please provide me with an alternative implementation without the use of the continue statement.
BTW I do not have tabs and spaces mixed as was suggested in another post.
Thank you for your help in advance.
continue is only allowed within a for or while loop. You can easily restructure your function to loop until a valid request.
def writeHandlesToFile():
while True:
with open("dataFile.txt","w") as f:
try:
lst = tweepy.Cursor(tweepy.api.followers,screen_name='someHandle',).items(100000)
print "cursor executed"
for item in lst:
f.write(item.screen_name+"\n")
break
except tweepy.error.TweepError as e:
print "In the except method"
print e
time.sleep(3600)
The problem might be in the way you are using continue
continue may only occur syntactically nested in a for or while loop,
but not nested in a function or class definition or finally statement
within that loop.6.1It continues with the next cycle of the nearest
enclosing loop.
How could I go about doing something like this
Try to do something.
If it works, great, continue with normal flow.
If it fails run a function and try again.
If it once again fails throw an exception and stop code.
I believe I would have to make use of try but I haven't quite come around yet to how to use it in this particular example.
It doesn't sound like you want to do a nested try-catch at all. Exceptions as control flow are a gnarly anti-pattern, and where you can avoid it, you should.
In this scenario, avoidance is easy. In the method that you describe, you want to be sure that a file exists before you do some operations on it. You also have a method to "correct" the path should it not. If both attempts fail, then you want to bail out.
With that into account, we would want to use os.path.isfile for this.
from os.path import isfile
def something(filepath):
# Don't mutate the parameter if you can help it.
p = filepath
if not isfile(p):
p = correct_path(p)
if not isfile(p):
raise Error("Cannot find file {} after correction to {}, aborting.".format(filepath, p))
with open(p, 'r') as f:
# Rest of file operations here
Try a nested try catch:
try:
do_something() #if this works, will skip rest and continue
except:
do_fix_function() #on error, do extra function
try:
do_something() #try again
except:
throw error() #if it fails this time, stop and throw an error
Note that if your do_fix_function() can also fail, you might want to put it inside the second try statement instead
This works for an arbitrary number of tries; I set it to two since that's what you want.
tries = 2
while True:
try:
step1()
except CatchThisException:
tries -= 1
if tries: # if tries != 0
step3()
continue # not necessary, just for clarity
else:
raise # step 4
else:
break # step 2
You can use retrying package to solve your retry attempt. Just write a block of code that keeps repeating on failure, until max retries is hit
For example:
import random
from retrying import retry
#retry
def do_something_unreliable():
if random.randint(0, 10) > 1:
raise IOError("Broken sauce, everything is hosed!!!111one")
else:
return "Awesome sauce!"
print do_something_unreliable()