Why the slogan?
I'm a big fan of Python. The syntax is great; the open-source community around it is extremely helpful; and the language lets me focus on the problems I'm trying to solve rather than the implementation details of the code.
A very peculiar feature of Python is that it comes with a set of ethical or aesthetic guidelines. My favorite -- because it's the most perplexing -- is the motto: "Explicit is better than implicit". It's perplexing because although it seems really simple (and maybe even obvious) when you read it, the more you think about it, the less clear it becomes. In fact, I think it's at least misleading, and probably wrong.
Like any programming language, Python makes a number of compromises. It aims for simplicity, and therefore hides quite a lot of details concerning how the interpreter works. Of course, you give up a lot when you don't understand the inner workings of the language. But Python allows you to surface a lot of its inner machinery if you want it. So you have the choice between either cruising along, happily skimming along the surface of the language and taking a deep dive into it.
One of the most conspicuous items that's missing from Python is type-checking. Functions don't care what they're passed, and no checking occurs before run-time. Instead, functions heroically try to perform whatever operations they've been told to perform, regardless of the types of their arguments. If the operation can be carried out, it's done. If it can't, we throw an exception. This is known, of course, as "duck-typing". Python doesn't care whether the thing actually is a duck. So long as it behaves like a duck, we'll call it a duck.
Here's an easy example. Suppose you've written a function that adds two things together.
We haven't had to declare the types of our function's arguments. It'll accept anything, and blithely try to add the arguments together. Here's where the duck-typing comes in. If we pass two integers to the function, it'll behave as expected by returning the sum. But if we pass in two strings, the function will also work: namely, by concatenating the strings together.
Python doesn't bother checking the types of x and y. Instead, it looks up their types and tries to find a method corresponding to the "plus" sign. If it finds one, the method is applied. So the function will work for strings, lists, ints, and floats, but not for sets. The upshot is that if you see a snippet of code that uses the plus sign, you have no idea whatsoever what that code does. The meaning of the plus sign is not explicit -- it's implicit.
It easy to come up with other examples in which the value of implicit functionality has been baked into Python. For instance, a common "gotcha" for people who are new to Python is how variables are passed to functions. Sometimes, they're passed by value. Other times, they're passed by reference. Mutable objects are passed by reference; immutable objects by value. Nothing in the code indicates this. It's implicit in the object's type. To take another example, method resolution order for multiple inheritance has a lot of implicit functionality under the hood. Which methods are used by a class with multiple inheritance is not something that's explicitly stated anywhere in the code.
Other than purely declarative programming languages, Python may have more implicit functionality than any other language I've come across. Which is why the "Explicit is better than implicit" slogan is so puzzling, and why it's the source of so many rants and arguments on StackOverflow.
I believe in *magic
The "explicit is better than implicit" slogan probably explains why there's such widespread resistance to so-called "magic" in Python. If you ask a question on StackOverflow about how to implement some Python magic -- for example, how to dynamically create classes or functions, or how to overload Python's import mechanisms -- you'll definitely get at least one answer saying, "Don't do it!". Python magic increases the amount of implicit functionality, and so there's often an assumption that if there's any other way to get something accomplished, magic should be avoided. So the fact that Python makes magic so easy is also another source of tension when people argue about the "best" way to implement something.
Personally, I think there's nothing at all wrong with having lots of magic and lots of implicit functionality in your Python code, even if it's not absolutely necessary. In fact, I think it's great! A couple of examples will help explain why I'm so strongly in favor of Python magic.
For my own work as a software engineer, I often write modules that are intended to be useful to other engineers. But of course, the mere fact that a piece of code would be useful doesn't by itself get other people to use it. There are high barriers to entry when you're learning how to use a new module. A common feature of modules that have a steep learning curve is that they require a pattern used in one piece of code to line up in some complicated with another pattern used in another piece of code. Consider a really simple example. Suppose you've got two functions that look like this:
The two functions have to "line" up correctly in order to avoid throwing an exception. The "sender" function gets a dictionary and builds a new dictionary by extracting some subset of its key-value pairs. The new dictionary is sent to "receiver" as a set of **kwargs.
If I were writing these functions for myself, I wouldn't bother doing anything fancy. But if I intended for someone else to be able to quickly implement functions like this, I'd worry a little bit. I'm forcing the other person to keep track of exactly which components of the dictionary are relevant to the "receiver" function. And this creates a set of "gotchas" that can be the source of much frustration. To take one example, this can happen if the module requires the user to subclass and provide a couple of methods that are required by the base class. (Scrapy works like this, for instance.)
Instead, why not let the code inspect the "receiver" function, get a list of its arguments, and automagically pare down the dictionary to include only the keys that the function needs? Python makes this easy to accomplish. The new dictionary can be programmatically defined like this:
This functionality could be baked into some base classes, or put into a decorator. It's magic, but so what? It would be nutty to write something like this if there was no intention for others to use the relevant code. But at the cost of a small bit of complexity and a bit of magic, we can free other people from having to worry about how the "sender" and "receiver" functions align with each other.
"Simple", "Complex", and "Complicated" don't mean anything
The "Explicit is better than implicit" slogan seems really plausible because it seems to be implied by the principles that "Simple is better than complex" and "complex is better than complicated". When a Python script does something implicitly, the code frequently becomes more complex. For a really clear example of this, check out the "sh" module, which hijacks Python's import mechanism and uses it to create functions that execute external commands. The effect of this is that you can "from sh import foo" and get back a "foo" function, even though no such function is actually defined in the sh module.
The module does this by doing a number of clever tricks. But is the module "complex? Or worse yet, "complicated?" There's no answer. Or more precisely, the answer depends on who you are. If you're a user of the module, there's nothing simpler. If you're a casual programmer poking around in the module's code, or someone who's looking to modify it, then it's probably "complex" (at least).
Simplicity isn't a characteristic of anything. It's a relationship. In programming, it's a relationship between three things: the code, the user of the code, and the purpose to which the code is being put. When those three align in the right way, you've got simple (and elegant) code. If they're out of alignment, then you've got something else -- in the worst case, it's complicated. The same code can be both simple and complex.
And this is why we too often assume that explicit is better than implicit. In typical use-cases, implicit creates complexity because of who the users are and what they're using the module for. But in many contexts, the opposite is true.