I was recently talking to a professor, who wanted us to realize the term “Art” in the title of Knuth’s book series “The Art of Computer Programming”. Just for the record for myself, I wanted to cite, what I was refering to when I explained him the true origins of “Art”:
People frequently ask me why I picked such a title; and in fact some people apparently don’t believe that I really did so, since I’ve seen at least one bibliographic reference to some books called “The Act of Computer Programming.”.
In this talk I shall try to explain why I think “Art” is the appropriate word. I will discuss what it means for something to be an art, in contrast to being a science; I will try to examine whether arts are good things or bad things; and I will try to show that a proper viewpoint of the subject will help us all to improve the quality of what we are now doing.
One of the first times I was ever asked about the title of my books was in 1966, during the last previous ACM national meeting held in Southern California. This was before any of the books were published, and I recall having lunch with a friend at the convention hotel. He knew how conceited I was, already at that time, so he asked if I was going to call my books “An Introduction to Don Knuth.” I replied that, on tile contrary, I was naming the books after him. His name: Art Evans. (The Art of Computer Programming, in person.)
As Stephen A. Goss points out correctly, the statements not (x == y) and x != y are not equivalent. Thomas and Karl wanted to know why.
I was guessing that different special methods are called, but let’s start from the beginning. python has the basic concept that any operator corresponds to a special method. Special method names start with two underlines (in most cases) and can be implemented by any class. This is the pythonic way for operator overloading. Facing the question I tried to disassemble the python code:
Okay, so when comparison is called, there are different parameters for the operator (please note that those parameters are not the values because python bytecode works stack-based and they got pushed before). A “3 (!=)” for a != 1 and a “2 (==)” for not (a == 1) followed by a UNARY_NOT. I really don’t know python bytecode by heart and therefore we had to look up the language reference.
There are no implied relationships among the comparison operators. The truth of x==y does not imply that x!=y is false. Accordingly, when defining __eq__(), one should also define __ne__() so that the operators will behave as expected.
So the simple explanation is that obj != obj2 calls obj.__ne__(obj2) and not (obj == obj2) calls obj.__eq__(obj2) and afterwards the __nonzero__ special method of the result of __eq__. For me it is pretty straight forward, because for all builtin types those calls behave the way you expect it to do so and using different operators invokes different source code. However, I don’t think that calling __nonzero__ is more intuitive than a __not__ method (which is restricted to the operator module). See the snippet and Guido’s rationale for more information.