Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is it "easier to ask forgiveness than it is to get permission" in Python?

Why is "Easier to Ask Forgiveness than it is to get Permission" (EAFP) considered good practice in Python? As a programming novice I have the impression that using many try...except routines will rather lead to bloated and less readable code than compared to using other checks.

What is the advantage of the EAFP approach?

NB: I know there are similar questions here, but they mostly refer to some specific example, while I am more interested in the philosophy behind the principle.

like image 257
n1000 Avatar asked Oct 02 '15 06:10

n1000


2 Answers

LBYL, the counter approach to EAFP doesn't have anything to do with assertions, it just means that you add a check before you try to access something that might not be there.

The reason that Python is EAFP is that unlike other languages (Java for example) - in Python catching exceptions is relatively inexpensive operation, and that's why you're encouraged to use it.

Example for EAFP:

try:
    snake = zoo['snake']
except KeyError as e:
    print "There's no snake in the zoo"
    snake = None

Example for LBYL:

if 'snake' in zoo:
    snake = zoo['snake']
else:
    snake = None
like image 102
Nir Alfasi Avatar answered Nov 14 '22 22:11

Nir Alfasi


You are mixing two things here: Assertions and EAFP-based logic.

Assertions are used to validate the contract of functions, i.e. its pre- and postconditions and sometimes also its invariants. They ensure that a function would be used in the way it should be used. They are not for code flow though, since they completely interrupt the execution on error. A common example is a check for None arguments in function calls.

In Python, you usually avoid using assertions too much. In general, you should expect users of your code to use it correctly. For example, if you document a function to take an argument that is not None, then it’s not necessary to have an assert that validates that. Instead, just expect that there is a value. If there is an error because of a None value, then it will bubble up anyway, so the user knows that they did something wrong. But you shouldn’t have to check everything all the time.

Now, EAFP is something different. It’s used in control flow, or rather, it avoids additional control flow in favor of expecting things to be correct and catching exceptions instead if they are not. A common example that shows the difference is a key access in a dictionary:

# LBYL
if key in dic:
    print(dic[key])
else:
    handleError()

# EAFP
try:
    print(dic[key])
except KeyError:
    handleError()

Now this looks very similar, although you should keep in mind that the LBYL solution checks the dictionary twice. As with all code that catches exceptions, you should only do it if the non-existance of a key is the exceptional case. So if usually, the supplied key is excepted to be in the dictionary, then it’s EAFP and you should just access it directly. If you don’t expect the key to be present in the dictionary, then you should probably check its existance first (while exceptions are cheaper in Python, they are still not free, so keep them for exceptional cases).

A benefit of EAFP here would also be that deeper down in the logic of your library or application, where the key comes from above, you can just assume that a valid key was passed here. So you don’t need to catch exceptions here but just let them bubble up to a higher point in your code where you can then handle the error. That allows you to have lower-level functions completely free of these kind of checks.

like image 35
poke Avatar answered Nov 14 '22 21:11

poke