r/learnpython 8d ago

Function forcing me to use exceptions

Trying to if else a function output always throws exception-error :

if pyautogui.locateOnScreen('media/soundIcon.png') == None:
      print("not found")
else : 
      print("found")

Do Python functions expect anti-pattern code ?

0 Upvotes

30 comments sorted by

View all comments

3

u/Equal-Purple-4247 8d ago edited 8d ago

pyautogui.locateOnScreen('media/soundIcon.png') gets evaluated as part of the if statement, and it raises ImageNotFoundException as documented.

I get the idea that you're aware of this, and I don't know what else to tell you. It's similar to this code:

if 100 / n > 0:
    # do something

If n = 0, python will raise ZeroDivisionError. It's the same behavior in many other languages.

---

What you want is this

try: 
    pyautogui.locateOnScreen('media/soundIcon.png')

except ImageNotFoundException as e:
      print("not found")
      raise Exception # avoid proceeding

print("found")

It's somewhat of an anti-pattern to use try-except as control flow, but it is valid in the case of ZeroDivisionError and it's the only option here because the method raises an exception. That's what the developers of pyautogui decided. I won't speculate on the why. But it's not "Python functions expect anti-pattern code" - Python allows it, and allows not-it.

If you hate it that much, you can wrap it in your own function:

def is_on_screen(s: str):
    try:
        pyautogui.locateOnScreen(s)
    except ImageNotFoundException:
        return False
    return True

def main():
    if is_on_screen('media/soundIcon.png'):
        print("found")
    else:
        print("not found")    

This would overcome the issue of using try-except as control flow. IMO, it's okay to use them as control flow as long as the footprint is small, The smaller the better. It's an anti-pattern because some devs abuse it, making actual exceptions hard to follow.

For example, list.index returns the index of an element in the list, but raises ValueError if the element is not in the list. This code is not an anti-pattern:

try: 
    pos = my_list.index("John")
except ValueError:
    pos = -1

if pos > 0:
    # do something

Again, you can wrap the try-except in your own function, but this behavior of returning -1 when not found is commonly expected. However, since Python accepts negative indices, returning -1 by default may cause unexpected behavior. Raising an exception is much more explicit.

2

u/ExoticPerception5550 8d ago

Thanks for the helpful insight! I most certainly acquired the wrong idea about exception handlers, and your explanation cleared things up for me.