Smash Company Splash Image

November 2nd, 2014

In Technology

1 Comment

Why not use asserts in Python?

(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: lawrence@krubner.com

I use asserts a great deal in Clojure. They partly take the place of unit tests. Apparently they are mostly unused in the world of Python, although some of the reasons listed here would be general to any language:

Several reasons come to mind…

It is not a primary function

Many programmers, lets not get bogged down by the rationale, disrespect anything which is not a direct participant in the program’s penultimate functionality. The assert statement is intended for debugging and testing, and so, a luxury they can ill-afford.

Unit Testing

The assert statement predates the rise and rise of unit-testing. Whilst the assert statement still has its uses, unit-testing is now widely used for constructing a hostile environment with which to bash the crap out of a subroutine and its system. Under these conditions assert statements start to feel like knives in a gunfight.

Improved industry respect for testing

The assert statement serves best as the last line of defence. It rose to lofty and untouchable heights under the C language, when that language ruled the world, as a great way to implement the new-fangled “defensive programming”; it recognises and traps catastrophic disasters in the moment they teeter on the brink. This was before the value of Testing became widely recognised and respected and disasters were substantially more common.

Today, it is unheard of, for any serious commercial software to be released without some form of testing. Testing is taken seriously and has evolved into a massive field. There are Testing professionals and Quality Assurance departments with big checklists and formal sign-offs. Under these conditions programmers tend not to bother with asserts because they have confidence that their code will be subjected to so much tiresome testing that the odds of wacky brink-of-disaster conditions are so remote as to be negligible. That’s not to say they’re right, but if the blame for lazy programming can be shifted to the QA department, hell why not?

These reasons are more specific to Python, but it is curious why the “optimized mode” is not used more commonly:

I guess the main reason for assert not being used more often is that nobody uses Python’s “optimized” mode.

Asserts are a great tool to detect programming mistakes, to guard yourself from unexpected situations, but all this error checking comes with a cost. In compiled languages such as C/C++, this does not really matter, since asserts are only enabled in debug mode.

In Python, on the other hand, there is no strict distinction between debug and release mode. The interpreter features an “optimization flag” (-O), but currently this does not actually optimize the byte code, but only removes asserts.

Therefore, most Python users just ignore the -O flag and run their scripts in “normal mode”, which is kind of the debug mode since asserts are enabled and __debug__ is True, but is considered “production ready”.

Maybe it would be wiser to switch the logic, i.e., “optimize” by default and only enable asserts in an explicit debug mode, but I guess this would confuse a lot of users and I doubt we will ever see such a change.

There is PEP which focuses on contract programming in Python:

This submission describes programming by contract for Python. Eiffel’s Design By Contract(tm) is perhaps the most popular use of programming contracts [2].

Programming contracts extends the language to include invariant expressions for classes and modules, and pre- and post-condition expressions for functions and methods.

These expressions (contracts) are similar to assertions: they must be true or the program is stopped, and run-time checking of the contracts is typically only enabled while debugging. Contracts are higher-level than straight assertions and are typically included in documentation.

Motivation

Python already has assertions, why add extra stuff to the language to support something like contracts? The two best reasons are 1) better, more accurate documentation, and 2) easier testing.

Complex modules and classes never seem to be documented quite right. The documentation provided may be enough to convince a programmer to use a particular module or class over another, but the programmer almost always has to read the source code when the real debugging starts.

Contracts extend the excellent example provided by the doctest module [4]. Documentation is readable by programmers, yet has executable tests embedded in it.

Testing code with contracts is easier too. Comprehensive contracts are equivalent to unit tests [8]. Tests exercise the full range of pre-conditions, and fail if the post-conditions are triggered. Theoretically, a correctly specified function can be tested completely randomly.

So why add this to the language? Why not have several different implementations, or let programmers implement their own assertions? The answer is the behavior of contracts under inheritance.

Suppose Alice and Bob use different assertions packages. If Alice produces a class library protected by assertions, Bob cannot derive classes from Alice’s library and expect proper checking of post-conditions and invariants. If they both use the same assertions package, then Bob can override Alice’s methods yet still test against Alice’s contract assertions. The natural place to find this assertions system is in the language’s run-time library.

This is an insightful phrase: “behavior of contracts under inheritance”. There is some cost to being a multi-paradigm language, and it shows in a situation like this, where 2 desirable goals are in conflict with each other. Ordinarily, faced with the need for a new control structure, Lisp programmers would say “That is what macros are for.” And, indeed, in a Lisp such as Clojure, there are multiple packages for enforcing contracts, and you can use the packages together without much worry of conflicts. But Clojure does not have to worry about inheritance. It really is the combination of “contracts under inheritance” that creates the need for this functionality to be in the core of the language.

I notice that PEP was introduced in 2003 and has gone nowhere since. I guess this idea is not popular in the Python community? I wonder why.

Source



Check out my book:





RECENT COMMENTS

December 16, 2018 9:06 am

From lawrence on Yair Lapid: What does it say about us that Israel has become the only democracy in the world in which Jews don’t have freedom of religion?

"Cat Mara, thank you for catching that. I've fixed it now. (The URL was a "v" by mistake. Looks like I was tryi..."

December 12, 2018 7:50 pm

From lawrence on Object Oriented Programming is an expensive disaster which must end

"Jussi Nurminen, thank you for writing. I believe you are correct, in the sense that Python 2.x had all the bas..."

December 12, 2018 5:13 am

From Jussi Nurminen on Object Oriented Programming is an expensive disaster which must end

"Hello! I've lately became a bit more suspicious of OO designs (including my own), so I read your original 2014..."

December 4, 2018 9:22 am

From lawrence on Docker is the dangerous gamble which we will regret

"GK, thank you for writing, but I don't understand what you mean when you write: "However, at that point you..."

December 4, 2018 7:14 am

From GK on Docker is the dangerous gamble which we will regret

"A development VM is a fine choice, provided that it comes with tools that make it just as easy to run commands..."

November 30, 2018 7:04 pm

From lawrence on Docker is the dangerous gamble which we will regret

"GK, thank you for writing. About this part: "That thing is writing portable shell scripts. The moment you n..."

November 30, 2018 1:41 pm

From GK on Docker is the dangerous gamble which we will regret

"The fat binaries article was nice, but full blown fat binaries are not really necessary. Whats needed is that ..."

November 27, 2018 1:13 am

From lawrence on Object Oriented Programming is an expensive disaster which must end

"Andres Moreno, thank you for writing. Among other points to be said, I'll say I'm almost heart broken about Py..."

November 26, 2018 9:11 pm

From Andres Moreno on Object Oriented Programming is an expensive disaster which must end

"I am stunned! Why did it take so long to show that the Emperor has no clothes? I got bit by the Lisp bug early..."

November 23, 2018 8:24 am

From Just An Observer on Hillary Clinton keeps making the same mistakes

"Similar to the "Let's dump Nancy Pelosi, since the Republicans don't like her" talk we hear all the time...."

November 22, 2018 11:49 pm

From Free Speech Message Board on Zed Shaw is angry (abstraction and indirection)

"Americans used to think hippies were lazy fruits for dropping out during the Vietnam War, but maybe the hippie..."

November 19, 2018 5:13 pm

From Justin McGuire on To start with, tran­sient query surges are no longer a prob­lem?

"I think the idea is that a surge in traffic results in more messages on the queue, which can be handled at a n..."

November 19, 2018 12:45 pm

From J on Docker is the dangerous gamble which we will regret

"What are everyone's recommendations for fat binary bare metal deployments preferably with hooks into continuou..."

November 19, 2018 11:07 am

From lawrence on Has the Internet destroyed our ability to read?

"Gábor Hidvégi, I agree with "too many pieces of information" especially small pieces of information. Most of t..."

1 COMMENT

November 7, 2018
6:04 pm

By Henry Longmore

Thanks for the article. I used to mock Eiffel for its “Design By Contract” as that seemed to be the only good reason to program in Eiffel. I was unaware of the PEP to add contracts to python. Another nice benefit of doing so as described in the PEP is that the tests (by way of invariants and contracts) are near the code being tested, which seems like it would make writing tests easier.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>