Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
59 views
in Technique[技术] by (71.8m points)

python - "Ask forgiveness not permission" - explain

I'm not asking for personal "religious" opinions about this philosophy, rather something a bit more technical.

I understand this phrase is one of several litmus tests to see if your code is "pythonic". But to me, pythonic means clean, simple and intuitive, not loaded with exception handlers for bad coding.

So, practical example. I define a class:

class foo(object):
    bar = None

    def __init__(self):
        # a million lines of code
        self.bar = "Spike is my favorite vampire."
        # a million more lines of code

Now, coming from a procedural background, in another function I wanna do this:

if foo.bar:
    # do stuff

I'll get an attribute exception if I was impatient and did not do the initial foo = None. So, "ask forgiveness not permission" suggests I should do this instead?

try:
    if foo.bar:
        # do stuff
except:
    # this runs because my other code was sloppy?

Why would it be better for me to add additional logic in a try block just so I can leave my class definition more ambiguous? Why not define everything initially, therfore explicitly grant permission?

(Don't beat me up about using try/except blocks... I use them everywhere. I just don't think it's right to use them to catch my own errors because I wasn't a thorough programmer.)

Or... do I completely misunderstand the "Ask Forgivess" mantra?

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The classical "ask forgiveness not permission" example is accessing values from a dict that may not exist. E.g.:

names = { 'joe': 'Joe Nathan', 'jo': 'Jo Mama', 'joy': 'Joy Full' }
name = 'hikaru'

try:
    print names[name]
except KeyError:
    print "Sorry, don't know this '{}' person".format(name)

Here the exception that might occur (KeyError) is stated, so that you're not asking forgiveness for every error that might occur, but only the one that would naturally occur. For comparison, the "ask permission first" approach might look like:

if name in names:
    print names[name]
else:
    print "Sorry, don't know this '{}' person".format(name)

or

real_name = names.get(name, None)
if real_name:
    print real_name
else:
    print "Sorry, don't know this '{}' person".format(name)

Such examples of "ask forgiveness" are often too simple. IMO it's not crystal clear that try/except blocks are inherently better than if/else. The real value is much clearer when performing operations that might fail in a variety of ways--such as parsing; using eval(); accessing operating system, middleware, database, or network resources; or performing complex mathematics. When there are multiple potential failure modes, being prepared to get forgiveness is hugely valuable.

Other notes about your code examples:

You do not need to ladle try/except blocks around every variable usage. That would be horrible. And you don't need to set self.bar in your __init__() since it's set in your class definition above. It is usual to define it either in the class (if it's data likely to be shared among all instances of the class) or in the __init__() (if it's instance data, specific to each instance).

A value of None is not undefined, or an error, by the way. It's a specific and legitimate value, meaning none, nil, null, or nothing. Many languages have such values so programmers don't "overload" 0, -1, '' (empty string) or similar useful values.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...