Python

De Morgan’s and (un)Pythonic code


The term “Pythonic” is a subjective and ambiguous one. There are plenty of sites on the internet that try to explain what it means. Some of the better sties will even tell you why one way of doing something is better than another. I am adding my scrollingtext to the latter list.

I believe that one of the key requirements for writing pythonic code is readability, as briefly mentioned in “The Zen of Python” by Tim Peters. I also believe that this little poem (I use that term loosely here) gives some pretty good hints on how to write pythonic code. (This is for more of the thought process outside the general coding style stuff defined in PEP-8). Here is the Zen of Python:

“Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
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.
Namespaces are one honking great idea -- let's do more of those!”

Since this post is about pythonic code, I want to take a quick moment to show you what I mean, saving you a google search or two in the process. Here is a class method that I would consider non-pythonic code:

  1. def inNodeExistInPool(self, poolName, nodeName):
  2. try:
  3. currentNodes = self.__getNodesInPool(poolName)
  4. if currentNodes:
  5. for n in currentNodes:
  6. if n == nodeName:
  7. return True
  8. return False
  9. except Exception, e:
  10. raise Exception('Exception in isNodeExistInPool: ' + poolName +
  11. ', Node: ' + nodeName + ', Error: ' + str(e))

Now here is a more pythonic version of the same code:

  1. def isNodeExistInPool(self, poolName, nodeName):
  2. try:
  3. if nodeName in self.__getNodesInPool(poolName):
  4. return True
  5. else:
  6. return False
  7. except Exception, e:
  8. raise Exception('Exception in isNodeExistInPool: %s, Node: %s, Error: ' %
  9. (poolName, nodeName, str(e)))

While the first version of the code above is not wrong and would probably be the correct way to do this in other programming languages, it’s not the best way to do it in python. (I also expect to see quite a few comments on how other python programmers might improve the first or second versions of these functions.)

Now that we have that little example out of the way, let me share with you the motivation for this blog post. At work one day I saw some code that looked like this:

  1. # ‘a’ being an instance of a class
  2. if not a.att1 and not a.att2 and not a.att3 and not a.att4:
  3. # more code down here

oddly enough, I remembered De Morgan’s Law from my formal logic courses, so I used it to simplify the expression. Here is the proof (in formal logic notation because it’s quicker):

  • ~P ^ ~Q ^ ~R ^ ~S
  • (~P ^ ~Q) ^ (~R ^ ~S)
  • ~(P v Q) ^ ~(R v S)
  • (~(P v Q) ^ ~(R v S))
  • ~((P v Q) v (R v S))
  • ~(P v Q v R v S)

After the logic juggling above I renamed the variables and then modified the code to resemble the ending result:

  1. if not (a.att1 or a.att2 or a.att3 or a.att4):
  2. # still more code down here

After the change we can immediately see that I’ve reduced number of not calls. While I’m sure there is some performance improvement, I seriously doubt that it’s something that might be noticed by a human being, so we’ll just discount this as any form of optimization. I believe I’ve also made the code easier to read. The line itself is smaller, so a maintainer would have less “things” to juggle in their head to verify that the expression should pass or fail. Thus this code change has fulfilled some of the ideas in the “Zen of Python,” particularly the parts about “Simple is better than complex,” and “Readability counts.” However, in the final product I’ve had to add some parentheses in order for the logic to be correct, and this is where my ultimate question lies. In a lot of “pythonic” code examples on the web, one doesn’t really see “if” statements written like this one. So a somewhat self-conscious part of me thinks that I even though I have gone through the trouble of trying to make the code cleaner, I still haven’t gotten the code to be “pythonic”.

After thinking about it a little more, I decided that my version is pythonic. While I did add some clutter by adding parentheses, I also removed 3 “not calls” and made the line easier to understand. I believe this follows the spirit of pythonic code, even if it does not follow the the code to the letter.

Top photo credit goes to: mromtz

99 bottles

It’s been a while since I put up one of these simple code posts. Let me fix that. :P

Quiet a while ago, this code needed to have the dust blown off of it. Programming Praxis had its readers program out the song for “Nintey-Nine Bottles of Beer on the Wall".

Here is my version of it:

  1. #!/usr/bin/env python
  2.  
  3. from __future__ import print_function
  4.  
  5. def output(in_int):
  6. if in_int != 1:
  7. return "%d bottles of beer on the wall, %d bottles of beer." \
  8. "You take one down, pass it around, %d bottles of beer" \
  9. "on the wall." % (in_int,in_int, in_int - 1)
  10. else:
  11. return "%d bottle of beer on the wall, %d bottle of beer." \
  12. "You take one down, pass it around, %d bottles of beer" \
  13. "on the wall." % (in_int,in_int, in_int - 1)
  14.  
  15. if __name__ == "__main__":
  16. [ print(output(x)) for x in reversed(xrange(1,99)) ]

That’s all there is to it really. The only enlightening thing about this I can say is that this algorithm reminds me a lot of my Code to lyrics post I wrote a little over a year ago. It’s amazing how simple songs are when they’re broken down to their basic elements. Anyone feel like setting up an “automatic song generation” business with me?

Git Pre-Commit Python Syntax

All of us programmers have made this mistake before: we’ve submitted code that we thought was correct only to have it fail during compilation because of a simple syntax error. Just between you and me (and the rest of the interwebs), I did this last week. Then I thought to myself that it would be good to come up with a tool to help ensure it didn’t happen again. I’m proud to say that on the Git front, I have fixed my problem.

Enter Git Hooks, a way to add scripts to various parts of the Git workflow. Using what is called the pre-commit hook, I was able to write up a quick bash script that goes through all the changed files in Git staging area, check if they are Python files (based on the .py file extension), and then run those Python files through Pylint to look for various errors, including syntax and type errors.

So here is my git hook:

  1. #!/bin/bash
  2.  
  3. files_modified=`git diff-index --name-only HEAD`
  4.  
  5. for f in $files_modified; do
  6. if [[ $f == *.py ]]; then
  7. pylint -E $f
  8. if [ $? != 0 ]; then
  9. echo "Code fails pylint check."
  10. exit 1
  11. fi
  12. fi
  13. done
  14. exit

Feel free to copy this and modify it for your own needs. My gift to you; no charge. But an occasional “Thank you Bryce” email is always nice. I also accept lavish gifts of cash or ThinkGeek merchandise.

One quick thing before I let you get back to your busy lives. If you have an older version of Pylint than 0.24, the “-E” flag might need to be changed to “-e”.

Project Euler: Problem 10

Thank you for your patience as you all (I'm sure) anxiously await my next posting.

Not only has it been a really long time since I posted something technical, it's also been a really long time since I posted a Project Euler solution. On that note, let's go over the challenge:

The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.
Find the sum of all the primes below two million.

Seems simple enough doesn't it? Let's find out. For Python the code is:

  1. #!/usr/bin/python
  2. """
  3. Python based code solution to problem 10 of project euler.
  4. """
  5. import math
  6.  
  7. def is_prime(divided):
  8. divisor = 3
  9. sqrt_divided = int(math.sqrt(divided))
  10. while divisor <= sqrt_divided:
  11. if divided % divisor == 0:
  12. return False
  13.  
  14. divisor += 2
  15.  
  16. return True
  17.  
  18. if __name__ == "__main__":
  19. print sum([2] + [x for x in xrange(3,2000000+1, +2) if is_prime(x)])

And for Haskell the code looks like:

  1. module Main where
  2.  
  3. prime_wrapper:: Int -> [Int]
  4. prime_wrapper divided = prime 3 divided (round . sqrt. fromIntegral $ divided)
  5.  
  6. prime:: Int -> Int -> Int -> [Int]
  7. prime divisor divided sqrt_divided
  8. | divisor > sqrt_divided = [divided]
  9. | mod divided divisor == 0 = []
  10. | otherwise = next_prime
  11. where next_prime = prime (divisor + 2) divided sqrt_divided
  12.  
  13. main :: IO ()
  14. main = print $ sum primes
  15. where primes = 2 : [ x | x <- [3,5..2000000], prime_wrapper x /= [] ]

I will be the first to admit that this problem is a little on the easy side. Mostly because you can reuse the code you created for problems 3 and 7, or at least I did. :)

Even though you and I know that Haskell will execute this code faster than Python, I feel I still need to uphold the tradition of posting my highly inaccurate execution times:

Python: 34.054s
Haskell: 20.690s

If you made it this far down into the article, hopefully you liked it enough to share it with your friends. Thanks if you do, I appreciate it.

Bookmark and Share

Syndicate content