Wednesday, August 7, 2013

Variable scoping in python and javascript

As I was reviewing a colleague's code a few days ago, I ran across the following:

Having spent the last few weeks reading through Code Complete, defining the variables outside the loop stuck out to me as a problem - a case of pre-mature optimization.  I suggested the following:

Reducing the scope of the variable just felt cleaner, and the discussions I found here and here seemed to back this up.

But when this came up when talking with a friend later in the day, he mentioned that he didn't think javascript even maintained scope inside "for" loops.  Coming from C++, I thought loops in both javascript and python would hold scope.  The following were our test functions, entered on the Chrome Developer Tools command line for javascript and the REPL for Python.

The output from both these tests are the same: x is defined.  This is because both python and javascript lack block scope, something very much present in C++.

In the particular case I was discussing, the choice becomes a big more grey.  There are strong opinions on both sides of the fence.  At this point I agree with the accepted answer on the linked StackOverflow discussion: "For the case where a variable is used temporarily in a section of code, it's better to declare var in that section, so the section stands alone and can be copy-pasted."  I think the use "var" can be as helpful for people as compilers, and it makes the intent of a block of code more clear.  Using "var" on a variable in a code block says to me that this variable is intended for use in this code block, and may not have any meaning outside of it.

Thursday, July 25, 2013

A Nose Specific Django Settings File

The Python Nose test framework has a several advantages over Django's default test framework.  I personally wanted to use Nose because of the xunit plugin which can output results in xunit format.  I needed this output format so that test results could be interpreted by Bamboo, the continuous integration solution we're using at my work.

For using Nose with Django, the django-nose package is an obvious choice.  However, it requires setting several settings values in your settings.py file that were only used by Nose.  Also, I like being able to run my tests using Django's default test runner.  I'm familiar with the output format, with the syntax for specifying how to run a single test, etc. and I didn't want to limit myself to running only Nose tests.

The approach I took was to create a new settings file for running nose tests.  This would contain just the settings needed for configuring django-nose, and import the main settings file to fill in the rest.  This is kind of the opposite of the usual pattern of importing a "local_settings.py" file at the bottom of your main "settings.py" to specify scenario specific settings (e.g. development vs production).

The comments in the script specify how to use it.  I hope it's helpful.

Wednesday, July 10, 2013

Duck Typing in Python

It has happened before, and it was happening again.  I had a weird problem, coded up an "interesting" solution, and then tried to find out why I felt strange about it.

In this case, I was writing a test function in a Django project to loop over a set of Tastypie api endpoints and make sure each endpoint responded without any errors.  To allow this test to grow with the file describing the api endpoints and to follow basic DRY principles I decided to import that file, find all the classes of a given type find the attribute I needed to build up the url of the corresponding api endpoint, and use the test client to render that url and check for errors.

My first attempt looked like this:


It may work, but it's not pretty. I'm explicitly checking whether each object I'm looking for is of the correct class, then I'm checking for an attribute, and after that I'm still having to wrap everything in an Exception to handle the case where the first argument to "issubclass" is not, in fact, a class.

So, with the smell of bad code wafting through the air, I went off in search of better solutions.  In this search I started in the place where all good programmer start: StackOverflow.

I started with this question about checking if a class is a subclass of another class.  At first I dismissed the comment about "python is not java" as a preachy comments on dynamic languages, but that got me thinking: I've heard the same people advocating duck typing and at the same time saying not to use exceptions to control flow.  I hadn't really put these 2 together solidly before, but now that I have this problem to work on, I see that these are quite related, and you can't have it both ways.  Either you type check, or you handle the unexpected with exceptions.

Coming from a HPC world, I instinctively avoided exceptions because they are usually though of as slow.  But after reading this very well phrased question on the topic of asking permission vs asking forgiveness (i.e. type checking vs. exception handling), my mind was starting to change.  In python the performance penalty is not so large that Exceptions need only be used for "exeptional" circumstances. After all, iterators are controlled with the StopIteration Exception, and that's part of the core language.

My mind was made after reading a third great question and response explicitly addressing duck typing.  The top answer recommends using Exceptions whenever possible as long as nothing really strange is going to happen if you try an operation on the wrong type of object.  Most of the time it's better to just document your functions well, let your users decide if they want to use it, and raise and Exception up to them if something went wrong.

So after all this, I went back and tried to put back together my simple function using what I learned.  I think the second take is more readable and probably just as fast as the original (the running of the test client for each url is definitely the bottleneck here anyway).  The substitution of the getmembers function of the Inspect module helps too.

If you were running into a similar problem with smelly code or preachy internet pythonistas, I hope this helps clear things up.

P.S. - The code snippets were embedded by adding the following snippet directly in the body of the post using the HTML editor feature of Blogger:

<script src="https://gist.github.com/[username]/[gistID]/[gistVersion].js"></script>