![](https://csdnimg.cn/release/download_crawler_static/10259206/bg10.jpg)
CHAPTER 1 ■ PRINCIPLES AND PHILOSOPHY
11
In the Face of Ambiguity, Refuse the Temptation to Guess
Sometimes, when using or implementing interfaces between pieces of code written by different people, certain
aspects may not always be clear. For example, one common practice is to pass around byte strings without any
information about what encoding they rely on. This means that if any code needs to convert those strings to Unicode
or ensure that they use a specific encoding, there’s not enough information available to do so.
It’s tempting to play the odds in this situation, blindly picking what seems to be the most common encoding.
Surely it would handle most cases, and that should be enough for any real-world application. Alas, no. Encoding
problems raise exceptions in Python, so those could either take down the application or they could be caught and
ignored, which could inadvertently cause other parts of the application to think strings were properly converted when
they actually weren’t.
Worse yet, your application now relies on a guess. It’s an educated guess, of course, perhaps with the odds on
your side, but real life has a nasty habit of flying in the face of probability. You might well find that what you assumed
to be most common is in fact less likely when given real data from real people. Not only could incorrect encodings
cause problems with your application, those problems could occur far more frequently than you realize.
A better approach would be to only accept Unicode strings, which can then be written to byte strings using
whatever encoding your application chooses. That removes all ambiguity, so your code doesn’t have to guess anymore.
Of course, if your application doesn’t need to deal with Unicode and can simply pass byte strings through unconverted,
it should accept byte strings only, rather than you having to guess an encoding to use to produce byte strings.
There Should Be One—and Preferably Only One—Obvious Way to Do It
Although similar to the previous principle, this one is generally applied only to development of libraries and
frameworks. When designing a module, class, or function, it may be tempting to implement a number of entry points,
each accounting for a slightly different scenario. In the byte string example from the previous section, for example,
you might consider having one function to handle byte strings and another to handle Unicode strings.
The problem with that approach is that every interface adds a burden on developers who have to use it. Not only
are there more things to remember, but it may not always be clear which function to use even when all the options are
known. Choosing the right option often comes down to little more than naming, which can sometimes be a guess.
In the previous example, the simple solution is to accept only Unicode strings, which neatly avoids other
problems, but for this principle, the recommendation is broader. Stick to simpler, more common interfaces, such as
the protocols illustrated in Chapter 5, where you can, adding on only when you have a truly different task to perform.
You might have noticed that Python seems to violate this rule sometimes, most notably in its dictionary
implementation. The preferred way to access a value is to use the bracket syntax, my_dict['key'], but dictionaries
also have a get() method, which seems to do the exact same thing. Conflicts like this come up fairly frequently when
dealing with such an extensive set of principles, but there are often good reasons if you’re willing to consider them.
In the dictionary case, it comes back to the notion of raising an exception when a rule is violated. When thinking
about violations of a rule, we have to examine the rules implied by these two available access methods. The bracket
syntax follows a very basic rule: return the value referenced by the key provided. It’s really that simple. Anything that
gets in the way of that, such as an invalid key, a missing value, or some additional behavior provided by an overridden
protocol, results in an exception being raised.
The get() method, by contrast, follows a more complicated set of rules. It checks to see whether the provided key
is present in the dictionary; if it is, the associated value is returned. If the key isn’t in the dictionary, an alternate value
is returned instead. By default, the alternate value is None, but that can be overridden by providing a second argument.
By laying out the rules each technique follows, it becomes clearer why there are two different options. Bracket
syntax is the common use case, failing loudly in all but the most optimistic situations, while get() offers more
flexibility for those situations that need it. One refuses to allow errors to pass silently, while the other explicitly silences
them. Essentially, providing two options allows dictionaries to satisfy both principles.