Monday, October 28, 2013

toolz and curry

Lightning talk


Doing a quick lightning talk tonight for PYPTUG @WFU and it wont be about spanners and food as the title might imply, but about...

Functional programming


Yes, about functional programming in an imperative by design language (Python). And it's a lightning talk, so it'll be very superficial. But hopefully interesting nonetheless.

My first experience with pure functional programming was in the 80s with the Miranda programming language. If one counts impure functional such as LISP, scheme etc, then that would be Logo as my first.

Back to Python

One of the most appealing Pythonic technique I use on a regular basis, is functional. But more on that later. Here in this talk, I'll focus on a new module called Toolz (the result of a merge of functoolz and itertoolz - with a z, not the standard library functools and itertools).


François
@f_dion

Friday, October 11, 2013

IEEE 754/854, when it is needed

Linkedin

There was a post on linkedin IEEE Computer Society group, lamenting the division by zero exception raised by Python, instead of returning infinity (or -infinity). I replied, but it is not that readable. So I'm putting the properly formatted reply on my blog. [edit: no comments followed on linkedin, but many appeared on the original source after that]

IEEE decimal

If you want IEEE 754/854 decimal behaviour, what you want to use is the decimal module:

>>> import decimal
>>> help(decimal)

The above typed in the python interpreter will provide all the help you need. The examples are a little verbose, however.


ExtendedContext


If you want to be shorthand, you can copy/paste the following at the top of your program:

from decimal import setcontext,ExtendedContext, Decimal as ieee
setcontext(ExtendedContext)


Then whenever you want to use ieee behaviour use ieee(value):

>>> 1/ieee(0)
Infinity
>>> -1/ieee(0)
-Infinity

Python does it right



It is good that it has to be explicitly stated that you want this. A division by zero should raise an exception when dealing with financial data[*]. I would recommend numpy if dealing with scientific data.


François
@f_dion

* Unless you are calculating my bonus...

Tuesday, October 8, 2013

$1 in Python

Interesting question


"Why cant I use $1 in a Python script to get the first argument to a script? What is the easiest way to do something like that in Python?"

$1 in a shell script gives us the first argument to the script, BTW.

I get a lot of questions through email, and in person. This one was part of an interesting exchange. The reasoning went like this, since the shell is processing the script, I should be able to use $1.

The problem is that it doesn't work like that. Dennis Ritchie introduced the #! (pound bang or shebang line) concept at Bell Labs and announced it publicly in 1980. In the exece function of sys1.c could be found the following:

 else if (u.u_exdata.S[0]=='#' && u.u_exdata.S[1]=='!' && indir==0) {
  cp = &u.u_exdata.S[2];
  while (*cp==' ' && cp<&u.u_exdata.S[SHSIZ])
   cp++;
  u.u_dirp = cp;
  while (cp < &u.u_exdata.S[SHSIZ-1]  && *cp != '\n')
   cp++;
  *cp = '\0';
  indir++;
  iput(ip);
  ip = namei(schar, 0);
  if (ip==NULL)
   return;
  goto again;
 
 
So, once it was established that a script started with #! and a variable number of spaces, what followed was the path to an executable that would process this script. No search, so it has to be a full path.

In that regard, if the line starts with #!/usr/bin/python or #!/usr/bin/env python, the shell is out of the loop and no $1. Python will process the script. There is an sh module that makes it appear like we are mixing Python and shell in one script, but it is still all Python code.

Simplest shell script


#!/usr/bin/bash

echo $1

Simplest Python


#!/usr/bin/env python
from sys import argv as s


print(s[1])

Fairly similar except we had to specify an import statement, and I aliased argv to s so it looked like $ in the shell script.

The "problem" (or difference) with the Python script is that it will error out if no arguments are given when run:

$ ./arg.py
Traceback (most recent call last):
  File "./arg.py", line 5, in <module>
    print(s[1])
IndexError: list index out of range

A closer equivalent



#!/usr/bin/env python
from sys import argv as s

print(s[1] if len(s)>1 else '')

Here we are simply testing to see how many items are in the argv list. The first item is the script name, so if we have >1 items, we have at a minimum one argument, so it is safe to get [1]. If not, we will return an empty string, just like a shell script would do. A try / except IndexError would have also worked in this context.

See also

I would also investigate argparse, opster and docopt. argv is really bare metal and there is no point in reinventing the wheel.


François
@f_dion