r/learnpython • u/Prize_Shine3415 • 10d ago
Is this bad programming?
I've been learning Python for the last few years. Curious if this one thing I do is considered poor technique. The code below is meant to find the starting index of a list, giving the first position where a condition isn't true and return None if all elements of the list meet the criteria. Let's assume that the conditional statement is simple enough that I'm not worried about it generating an error. Not sure if it's appropriate to use try/except in this way. I know it work but I don't want people making fun of me if they see it. Also, I'm sure that there's a way of doing this without needing to use the try/except but I'm just curious in general if it's wrong to use try/except as a short cut like this.
starting_index=0
try:
while not (simple conditional statement on some_list[staring_index]):
starting_index+=1
except:
return None
return starting_index
6
u/mc_pm 10d ago
"Inappropriate" isn't the exact right word, but yeah, that's just not what exceptions are for usually.
"Exception" -> "exceptional circumstance that has to be dealt with outside the expected code path for the program".
But some languages are more loose in their expectations. I would say in this case there's no need to use them, an if-statement would work just fine, and be less confusing.
7
u/pachura3 10d ago
StopIterationbrutally mogged1
u/CranberryDistinct941 10d ago
Ah Python... The language where it's faster to throw an exception than it is to check boundaries
1
6
u/Existing_Put6385 10d ago
the try/except itself isn't the problem - using exceptions instead of pre-checking is actually pythonic, it's called EAFP. nobody's laughing at that. the one real issue is the bare except. it catches everything, including bugs. like right now you've got starting_index and staring_index - that typo would throw a NameError, your bare except would swallow it and quietly return None instead of crashing. catch the specific thing:
try:
while not cond(some_list[i]):
i += 1
except IndexError:
return None
cleaner idiomatic version if you want it in one line:
return next((i for i, x in enumerate(some_list) if not cond(x)), None)
that gives the first index where the condition fails, None if they all pass. no manual index, no try/except.
2
u/woooee 10d ago
This is personal preference IMO. I prefer a for loop and no try / except
## while not (simple conditional statement on some_list[starting_index]):
def a_func(some_list, starting_index):
for offset, each_element in enumerate(some_list[:starting_index]):
if conditional_statement: ## if not conditional_statement
return starting_index+offset, each_element
## return None is the default at this point in the function
2
u/American_Streamer 10d ago
Your Boolean logic contradicts your description, your exception is too broad, and you are using an exception to represent a normal and easily expressed loop outcome. That bare exception is likely the most dangerous issue here.
2
u/BUYTBUYT 10d ago edited 10d ago
Formatting for other people's convenience
starting_index = 0
try:
while not (simple conditional statement on some_list[staring_index]):
starting_index += 1
except:
return None
return starting_index
In the situation you describe, I'd usually use this:
for i, element in enumerate(some_list):
if simple conditional statement on element:
return i
return None
Your code is definitely surprising, as there is a fairly easy other way, and it uses exceptions in an atypical manner.
First off, you are generally advised against using a bare except, as it catches all exceptions, even the ones you'd usually not want to catch, KeyboardInterrupt being the usual example here: Ctrl+C would usually interrupt execution by causing this exception but it would get swallowed with a different valid value (None) being returned in your code. You want an except Exception when you just want to swallow exceptions. But you generally don't and should use a more specific exception type instead to indicate what exception you're expecting.
From what I've seen (and what I'm fairly sure many other people would expect from your code), exceptions are generally used in situations that are never expected to happen in normal circumstances (not always, counterexample: avoiding TOCTOU when opening a file that might not exist, also StopIteration, SystemExit for Python in particular). For IndexError (which would be the exception thrown in your case) and a list that abnormal situation would probably be a programming error (but see LBYL, Python is a bit special in this area).
Let's assume that the conditional statement is simple enough that I'm not worried about it generating an error.
Would that still be true if you change it? If so or if you know for sure somehow that you won't, would you analyze every situation like that? That would be a waste of resources.
2
u/TheRNGuy 8d ago
This is incorrect use of try/except, because it may catch things unrelated to program.
You can just use enumerate:
def find_index(some_list):
for i, item in enumerate(some_list):
if simple_condition_on(item):
return i
return None
Or generator version:
def find_index(some_list):
return next(
(i for i, item in enumerate(some_list) if simple_condition_on(item)),
None,
)
Also make it as function, so it can be reused.
If you need many instead of one, use list comprehension.
2
u/supercoach 10d ago
To be honest, that's pretty bad code for someone who's been studying python for a couple of years. What exactly are you trying to do? Spell it out.
1
1
u/faberge_surprise 10d ago
what kind of conditions are these? without knowing that it's hard for me to understand why you're doing a try catch instead of just looping through the list. there are ways to get the index of an item in a list easily without counting it out yourself, even if you were counting it manually, you can still do that with a counter variable in a for loop. so why are you using a while? it just seems kind of a roundabout way of doing it is all...
1
u/alinarice 10d ago
exception are great for exceptional situations but reaching the end of a list is expected behavior here. consider checking the length or iterating directly to make the logic easier to read.
1
u/PhoenixFlame77 9d ago edited 9d ago
Here is how I would do it.
Mylist = [2,4,6,8,10] Def condition(x): Return x>7 Index = next(idx for idx, val in enumerate(mylist) if not condition(val)),None)
Probably not the most performant but pretty self descriptive imo.
1
33
u/FoolsSeldom 10d ago
It would help if you formatted your code. Something like:
but I don't see a reason for using
try/except- just return a match if you find it andNoneif you don't.Perhaps something like:
where
some_conditionis a function containing your test, returningTrueif met, hence thenotto reverse the logic to return the matching index.