PyCon Canada 2017: “Python as a Philosophy”

I was in Montreal, Canada for the PyCon Canada 2017 conference and presented on the ideas and philosophy that are present within the Python programming language. I covered how the Python language influences your coding style and how that coding style is now in the mainstream and has made its way into other programming languages.

In the presentation I used PEP20, the Zen of Python, document as the starting point. PEP are the Python Enhancement Proposals and the Zen of Python was one of the earlier of these proposals.

The ideas within Zen of Python that I further examined are:

  • Explicit is better than implicit
  • Errors should never pass silently
  • If the implementation is hard to explain, it’s a bad idea
  • If the implementation is easy to explain, it may be a good idea

Jupyter Notebooks

Jupyter notebooks embodied parts of the Zen of Python, in particular that “explicit is better than implicit”. Jupyter notebooks (formerly know as IPython) has risen in popularity as it is being used for data science. Data scientists all rely on the notebook style to express their thoughts and to show their work and code. You can use Jupyter notebooks at Google Colab and Microsoft Azure, and see rendered versions of them in GitHub code repositories.

Peter Norvig, director of research at Google, uses Python heavily and created some IPython/Jupyter notebooks. You can see a rendered version of one of his notebooks on Github. What’s cool here is the space for explanation, including charts and graphs and mathematical formulas. The notebook is close to an interactive textbook.

Also, Jupyter notebooks supports many languages today including Python, Haskell, Ruby, R and Scala so you aren’t restricted to just Python. This is an example of the Python philosophy reaching beyond that one programming language and into other languages and domains.

Sphinx Documentation and Docstrings in Python

Within Python, you have the ability to create documentation using docstrings which aides in readability. Docstrings give developers a space to be more explicit about the intent of the code and to explain it.

The next project that I examined which embodies parts of the Zen of Python was the Sphinx documentation project.

Sphinx is how most Python-based projects generate their documentation and it generates it by using the docstrings that are part of the code. The default configuration of Sphinx produces good looking documentation with an index and a basic search engine.

Sphinx embodies and enables the idea that beautiful is better than ugly, that explicit is better than implicit. The markup language itself is complex, but not complicated, and is simple if you stick to the basics. So there are many points at which Sphinx embodies the Python philosophy.

The Design of Python APIs

Next there are the way Python APIs for libraries are designed. Python libraries have great API designs. I feel that the Python philosophy and the Zen of Python can take some credit for this.

The APIs of many Python libraries are sensible, they are explicit, they are explained well, they are readable. The Python philosophy strongly influence how Python libraries are written.

And this is just in Python, let’s see where else the Python philosophy has made an appearance.

JavaScript and the Zen of Python

In JavaScript, the Python philosophy has had a weaker influence. Though that may start to change, since there are Python developers who are switching to JavaScript and we should see more well-designed libraries that value readability, beauty, simplicity and so on.

One example that I want to point out is Express.js. Express is a Node.js-based web framework. In their code they have a router which dispatches from a url pattern to a controller. You may know this as the urlconf file in Django or as a url resolver.

JavaScript even with the additional new language features of ES2015 is very un-Pythonic. However, it still can express some of the Python philosophy, though at a higher level. JavaScript is made for interactivity which makes it ideal for interactive explanations of code.

We can see this at Khan Academy which uses interactive lessons to teach students. We can see it with specific libraries like d3 used for data visualizations that are created by the New York Times and other newspapers. As mentioned, Jupyter allows charts to be made and in the browser they’re rendered with JavaScript. Also, Sphinx.js was made to improve Javascript’s documentation.

So the story in JavaScript is that it’s difficult to express the Python philosophy except at a very high-level in terms of documentation and user-friendly tooling and better API designs.

Ruby and the Zen of Python

However, Ruby is a different story. Through my career I have encountered Ruby code that bears a strong resemblance to Python.

For example, pulling function parameters into their own local variables:

def before
  hello 'world', 123
end

def after
  name = 'world'
  repetitions = 123
  hello(name, repetitions)
end

This greatly improves readability and makes it simple to debug whether you’re using a proper debugger or print statements. Since the variable parameters are separate from the function call, you can print their values out before the function is called.

Another example of explicitness and readability in Ruby code that I recently worked on was for testing method calls.

Originally we had many tests relying on our test library to ensure that the method calls were accurate and had particular arguments passed to them. It was tedious work because we had to find a specific method call in the list of method calls and then test the arguments.

To match a list of method calls, it looked something like this:

describe 'method call test' do
  it 'calls the method with 1, "abc", :hello' do
    expect(MyClass.method_calls).to eq []
    MyClass.do_things
    expect(MyClass.method_calls).to eq([
      [:abc, [1, 2, 3, '127.0.0.1', 'b1d4a2', '45be3f']],
      [:def, [3, 2, 3, '127.0.0.1', 'b1d4a2', '45be3f']],
      [:efg, [3, 2, 4, '127.0.0.1', 'b1d4a2', '45be3f']],
      [:hij, [3, 2, 4, '127.0.0.1', 'b1d4a2', '45be3f']],
    ])
  end
end

The new code now looks like this:

describe 'method call test' do
  it 'calls the method with 1, "abc", :hello' do
    expect_do_things_call(:abc,
      :id => 1, :other_id => 2, :thing_id => 3, :ip_address => '127.0.0.1',
      :role_id => 'b1d4a2', :category_id => '45be3f'
    )
    expect_do_things_call(:def,
      :id => 3, :other_id => 2, :thing_id => 3, :ip_address => '127.0.0.1',
      :role_id => 'b1d4a2', :category_id => '45be3f'
    )
    # ...more of the above...
  end
end

The upside is that the test is explicit in the arguments and parameters that will be passed to the method. The expectation is far more clear and it increases readability.

Tests are used to double-check our work but if the code in those tests is dense, nested and hard to understand, then we can’t double-check our work effectively. The Python philosophy of readability and explicitness is at play here.

I would also say that the “flat is better than nested” and the “sparse is better than dense” concepts in the Zen of Python are also at work.

Conclusion

While some of the ideas here are essential to good software development and software engineering, they are uniquely embedded within Python.

These ideas are embodied within the Zen of Python which sets the standard and affects Python and its community. With Sphinx and Jupyter, the Python philosophy becomes more widespread.