How to Write a Python Switch Statement

I’ll admit, I don’t use switch statements very often when programming. When I do, it has always been in Javascript. So when I found myself wanting to use a Python switch statement recently, I discovered that the switch/case statement doesn’t exist in the language.

The Python Switch in a Nutshell

If you don’t want to read a long article, here are the basics on how to implement a switch statement in Python. You simply need to create a Python Dictionary (otherwise referred to as an associative array) where the key is your case choice and the value is what gets returned. Then call the dictionary get() method to return the value based on the case.

Here’s what the Pythonic switch-like statement looks like:

def switch(arg):
switchy_thing = {
"case 1": "something",
"case 2": "something else",
"case 3": "something big",
"case 4": "something bigger" ,
"case 5": "something huge!!",
"case 6": "Some really ginormous thing!!!"
}
return switchy_thing.get(arg, "Nothing")

print switch("case 4") #prints "something bigger"

Let’s take a closer look at what’s happening here. Inside the switch function, Switchy_thing is a dictionary containing six “case” statements. These are actually just key/value pairs. After the dictionary is defined, we call the built-in get() method in order to get the value we want out of the dictionary.

The get() method takes in two parameters. The first parameter is the name of the key with the value you are trying to have returned. The second parameter is the default value that get() will return if the key you passed doesn’t exist. This is analogous to the default statement inside of the switch statements of some languages. If our example above called switchy_thing.get(“case 10”, “Nothing”) , it would return “Nothing” since there is no key called “case_10.

dictionary.get(key[, value]) 

As an alternative to using dictionary.get(), you can retrieve a key’s value using square bracket notation with the dictionary name. In our example, to get “case 6” we would write switchy_thing[“case 6”] which would return “Some really ginormous thing!!!”. The problem with doing it this way is there’s no default value failover. If you call switchy_thing[“case 10”] you will get an error.

Here’s how an actual switch statement works in JavaScript:

let someVariable = 5;

switch(someVariable){
case 1:
Some code block...;
break;
case 2:
Some code block...;
break;
case 3:
Some code block...;
break;
case 4:
Some code block...;
break;
case 5:
console.log("case 5 was selected");
break;
case 6:
Some code block...;
break;
default:
"A bad value was entered";
}

//logs "case 5 was selected"

If you’re a JavaScript developer like me, you’ll recognize the code example above. There are several similarities between the JavaScript switch and our Python implementation. First, both look like key value pair constructs.

Both are wrapped in curly braces and separate the cases/keys from the return value with a semi colon. Both have a default value (if you use the get method with the Python implementation).

There are also some differences. The JavaScript default is contained in the body of the switch statement while we’re sort of hacking it in there with Python’s get(). Also, you’ll notice that there’s a break statement in each of the JavaScript case statements that are not present in our Python code. JavaScript doesn’t just jump out of the switch statement when a case is found true. Without the break keyword, control of the switch statement will simply fall through to the next case. It will keep doing this until it hits a break or gets to the default. For example, you could write this in JavaScript:

function pennyWise(year){
switch(year){
case "1858":
console.log("flying eagle cent");
break;
case "1877":
console.log("indian head cent");
break;
case "1910":
case "1934":
case "1977":
case "present":
console.log("Lincoln penny");
break;
default:
"A bad value was entered";
}

pennyWise("1877"); //logs "indian head cent"
pennyWise("1934"); //logs "Lincoln penny"
pennyWise("present"); //logs "Lincoln penny"

We don’t need a break statement in our Python switch because by its nature it only allows a single decision to be made. This is a good thing unless for some reason you rely on this kind of multiple-case behavior.

Come to think of it you can sort of implement the above multiple-case behavior in Python but with an, if statement and the keyword or. You could write:

def switch(val):
if val == 0:
print "you printed zero"
elif val == 1 or val == 2 or val ==3 or val == 4:
print "you printed something between 1 and 4"
else:
print "You don't know how to count"

When do you want to use a switch-like statement in Python?

The case (this pun was stumbled upon and intentionally left in) for using a dictionary/switch statement rather than an if-else is really all about clean looking code and having to write less of it. There might be an argument where one or the other performs better with huge data sets but most of us won’t have to deal with data of that magnitude.

If you do happen to be a big data junkie, all I’ll say is that … it probably still doesn’t matter. It’s not worth worrying about unless your code is slowing to a crawl. Even then it might not be your branching logic that’s at fault. In situations like this, you’ll want to profile your code and try to figure out exactly where the blockage is.

So basically, you’ll use the switch-like statement whenever you feel like it. A good rule of thumb is to use it when you have more than ten if-elif blocks. Even then, it’s just for human readability optimization rather than computer performance optimization.

Why is there no switch statement in Python?

My use case that prompted this post wasn’t that exciting or important. I probably could have just used a slightly larger than usual if/elif statement to do the work. But I hate not knowing how to do something or why something is missing. So I set out to research the mysteriously missing Python switch.

Turns out, it’s not that mysterious after all. Guido van Rossum and the Python team have never put it in the language. They didn’t think it was necessary. In fact, in the official documentation, there’s really no reason given. It basically tells the reader to deal with it and use if/elif/else statements where you just keep adding elifs for each case you want to include.

The docs go on to say that if you have a lot of cases to choose from you can set up a dictionary mapping to emulate a switch. Oh, hey, that’s what were doing in this article!

None of this is to say that no one wants a switch-case statement in Python. There have been a couple of proposals put before the Python team with solutions to a supposed problem. But each time switch comes up it gets rejected. It’s unlikely to ever become a part of the language.

Conclusion

While Python doesn’t have a native switch implementation, it’s fairly easy to emulate the functionality using dictionaries and its built-in get() method. Or, instead of trying to patch together a switch, you can just use if – elif – elif … until you’ve listed all of your cases. Then you can use the else clause as your default value. There’s really no performance advantage to either one for most programmers. But once you get more than, say, 10 elifs, your code can start to look a little messy. At that point, you might consider the dictionary/switch syntax. Beyond that it doesn’t really matter.

Search Directory Trees with Python

Here is a simple but powerful way to use Python to search and find all files with a specific extension within a given folder and all of its sub-folders using os.walk(). I use it a lot to find map documents with broken data sources, images that need to be organized or just to get a quick count of certain files in a directory.

import os

directorypath = raw_input("Enter a directory path: ")
extension = raw_input("enter an extension: .")

#Loop through all folders and subfolders in your target directory. 
for root, dirs, files in os.walk(directorypath):
    fileList = [os.path.join(root, f) for f in files if f.endswith(extension)]             
    for item in fileList:
        print item #or do something else with each file found.

 

When Django Met IIS

The Problem:

The county I work for had a one page geography quiz with outdated questions and a poorly structured user interface. It was just an unstyled list of select dropdowns and a submit button. The answer page that was returned just listed each question with all the answer choices under them. One answer under each question was highlighted in yellow but it wasn’t made clear to the user whether this was the correct answer or just the answer they chose.

Old Mesa County quiz app.To compound things, the quiz was stuck in an enterprise CMS that gave it a really ugly url. I wanted to change that so it would look good and be really easy to understand. Thankfully I wasn’t restricted to any particular language or technology stack to build the new quiz.

The Solution:

A few years back I had played around with Django and thought it was a cool framework but I had never really applied it to any project. So I said to myself “why not?” and set out to build a new geography quiz app with Django. Over the next couple of days I put together the components of the new application:

  • A PostgreSQL database to store the questions and answers
  • Models to define the data in the database
  • Views to process and send the data and to route user answers to the answer page
  • Templates to render the data

Everything seemed to be going along smoothly although I wasn’t very happy with the way I wrote my views to handle the user submitted answers. The app basically builds a form on the fly (questions with radio button answers) then does a POST when the quiz taker clicks the submit button. The view then takes the POST data and turns it into a Python list. The rest of the view just slices and dices the list and uses offsets to pull out the matching questions and answers.

I know there are cleaner ways of doing this. Especially since the returned POST data is a querydict object which is basically just a Python dictionary. Manipulating key/value pairs seems neater. But the way I did it worked and I got it up and running fast. Maybe a project next time I’m bored will be to make the code cleaner and more maintainable.

Another Problem:

Remember earlier when I said that I asked myself “why not?” when considering using Django? Well, I was about to answer that question and the answer wasn’t pretty.

While I was developing my quiz app I used Django’s built-in server which is a lightweight “please don’t use in production” server. It worked great. Then I decided it was time to port the app to my production server and actually use it in the real world. At that point I remembered we use IIS on a Windows server.

IIS isn’t all bad, especially if you work in a place that uses .NET components heavily which I do. Unfortunately, Django was never really developed to run on IIS. Django was really designed to live in a Unix world and be served out with something like Apache. I remembered that from my prior experience with the platform – I just forgot.

Another Solution:

There are several tutorials on the web (most of them several years old) that discuss running Django under IIS but none of them were very straight-forward. The solution that seemed like the quickest route to a running app was to use Helicon’s Python Hosting Package (part of the Helicon Zoo repository available through the IIS Web Package Installer). The hosting package basically loads all of your dependencies and does all of the complicated work of getting IIS to run an antagonistic technology. You then load a Python Project module which builds everything for you including:

  • A virtual Python install specific to your app
  • A web config file with needed environment variables
  • Permissions and application pool settings

The only pain point I had with using Helicon’s solution was discovering it doesn’t work with Django 1.7. I had developed in 1.7 and then when I migrated into the Helicon environment everything broke. This really threw me for a loop for a while until I found a post suggesting using Django 1.6. This didn’t turn out to be a big deal as it didn’t affect my apps functionality. I just had to remove a couple of middleware classes from my settings file and I was good-to-go.

New Mesa County Quiz AppConclusion:

I love working with Django. If I wasn’t in a Windows environment I might be trying to use it throughout my office GIS site. But I can’t see trying to force uncommitted technologies into a relationship they don’t even seem to want. I guess Django is just going to be a hobby framework for me for now. Fortunately there are plenty of others out there just waiting to be learned and implemented.

Installing Setuptools and PIP for Python

Python logoI’ve installed a lot of Python packages over the years using Distutils, SetupTools/easy_install and PIP. Distutils is Python’s built-in package distribution module and is pretty easy to use. However, it has some limitations, primarily that you have to manually download the package dependencies and there is no method to uninstall packages.

The Setuptools easy_install script takes care of downloading packages and package dependencies but still lacks certain features you would want from a fully functioning package manager. It doesn’t provide version control support, package tracking and uninstallation. There is a lot more to the Python package discussion but there is no point in bringing it up.

Anyway, while I use package distribution tools I rarely have to install the tools themselves since they only get loaded once. When I do have to set up a new machine or upgrade someone elses, I always forget the steps to get Setuptools and PIP installed. So I thought I would document the steps here. Now I just have to remember to come back here when I need them.

 Installing Setuptools:

1. Right click on this ez_setup.py link and save the file to your Python Scripts folder (If you have ArcGIS loaded you will usually find this at C:\Python27\ArcGIS10.x\Scripts).

2. Open a command prompt and change into the SCRIPTS directory.

3. Type

python ez_setup.py

then hit enter to execute the code. This will run the script which will download and install setuptools on your system.

For the official installation instructions for setuptools, which includes instructions for installing on Windows 8 with Powershell visit https://pypi.python.org/pypi/setuptools.

Installing PIP:

1. Open a command prompt and change into the C:\Python27 directory.

2. Type

easy_install pip

then hit enter to execute. Pip should now be installed on your system.

To actually install a package using PIP from a command prompt you simply type

pip install "PackageName"

and everything will be taken care of for you. To explore the more than 54,000 packages that are available for Pip to load visit PyPI – the Python Package Index.

Use Python to Keep Your Brain Sharp

“Use it or lose it” certainly applies where brain function is concerned. The experts tell you to exercise your brain to keep it in shape and ward off forgetfulness and possibly dementia when you are older.

One way to exercise your brain is to do computations in your head. Not long ago I read a book called The Power of Forgetting by Mike Byster that introduced several tricks and methods for doing these mental computations. One that stuck with me was how to multiply two, two-digit numbers in your head. Here’s an excerpt from the book explaining how to do it:

addnumbersThere are probably easier ways to do mental multiplication but Byster’s method is meant to be an exercise in remembering and forgetting numbers at will to make your brain stronger.

I wanted to find a way to challenge myself with the above multiplication method on a regular basis. My solution was to write a very small Python script that would generate random two-digit by two-digit multiplication problems and display them on screen. Here is what I came up with:

from random import randint
from ctypes import windll

firstNumber = randint(10,99)
secondNumber = randint(10,99)

problem = str(firstNumber) + " x " + str(secondNumber)
answer = str(firstNumber*secondNumber)

windll.user32.MessageBoxA(0, problem, "Can you multiply these in your head?", 0)
windll.user32.MessageBoxA(0, "The answer is: " + answer, "How did you do?", 0)

The script simply generates two random two-digit numbers, displays them to the user, then displays the correct answer when the user closes the first message box. I used Python’s ctypes library to create Windows message boxes,so you would need to make some adjustments if you wanted to use it on a different operating system. I also set up my task scheduler to run the script automatically every hour. Now, throughout the day at work and at home I’m reminded to exercise my mind in a way I wouldn’t normally exercise it.