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

两盒软妹~` 提交于 2019-12-06 05:43:35

问题


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.


回答1:


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



回答2:


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.




回答3:


Nice question! There are very few questions in StackOverflow asking about "the philosophy behind the principle".

Regarding to the EAFP definition in Python glossary, I would even go further and say its mentioning of "caches exceptions if the assumption proves false" is somewhat misleading in this context. Because, let's face it, the following 2nd code snippet does NOT look more "clean and fast" (a term used in the aforementioned definition). No wonder the OP asked this question.

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

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

I would say, the real moment when EAFP shines, is that you do NOT write try ... except ... at all, at least not in most of your underlying code base. Because, the first rule of exception handling: do not do exception handling. With that in mind, now, let's rewrite the 2nd snippet into this:

# Real EAFP
print(dic[key])

Now, isn't that real EAFP approach clean and fast?



来源:https://stackoverflow.com/questions/32901886/why-is-it-easier-to-ask-forgiveness-than-it-is-to-get-permission-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!