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.