Treating Python Functions as First Class Objects
For this Bench Press post, I wanted to discuss a relatively unused feature in Python which I found to be a big help while doing some Benchside-related coding. For many coders, the programming experience centers around C, C++, and/or Java. While these three languages are still widely used and are as prominent as ever, the transition from these “C-like” syntaxes to Python can be a bit tough. Oftentimes, programmers learn only a portion of Python’s syntax and proceed to write “Java-like” Python. As a result, their Python code can become unnecessarily long, inefficient, and un-Pythonic, mainly because the best way to write a program in Java isn’t always the best way to write it in Python.
While there are many ways to write Pythonic code, one of the key features most people typically don’t employ is the use of functions as first-class objects. To see what I mean by first-class object, let’s take a look at the following Python functions:
def sumOfSquares(a, b):
return a**2 + b**2
def sumOfCubes(a, b):
return a**3 + b**3
def sumOfNegatives(a, b):
return (-a) + (-b)
While these functions will do the job, each function essentially performs the same duty, only with minor adjustments. As a programmer, you should have alarms going off, as one of the cardinal sins in programming is to write redundant code. While there are solutions to this in C, C++, or Java (such as using templates), none are as clean, in my opinion, as Python’s:
def square(a):
return a**2
def cube(a):
return a**3
def negative(a):
return -a
def sum (a, b, function):
return function(a) + function(b)
For our examples, sumOfSquares becomes sum(a, b, square), sumOfCubes becomes sum(a, b, cube), and sumOfNegatives becomes sum(a, b, negative). What makes this Pythonic solution more impressive is that the function sum actually takes in as an argument a function (in our case, square, cube, and negative)! Not only does this allow sum to be generalized for other functions (for example, square root or double), instead of writing out sumOfSquares, sumOfCubes, etc. we simply need to invoke the sum function with the proper function.
In addition to being passed as an argument, first-class functions can also be stored within data types (like lists and dictionaries), returned from functions, and referenced by variables. If you are new to this style of programming, I recommend reading a few Python tutorials on how to use higher order functions and experimenting on your own.
Extra for experts: For those C/C++/Java wizards out there, yes I realize C and C++ have similar functionality using function pointers, and that Java has a built-in function object interface. However, each of these generally requires a very messy implementation and aren’t usually taught in standard courses. Furthermore, you will find that Python’s support of higher order functions is much more expansive and well-documented (such as built-in support for map, reduce, and filter operations).
Also, some of you may find that my example above skimped out on my example because I haven’t actually declared a sumOfSquares or sumOfCubes. I agree, while sum(a, b, square) is equivalent to sumOfSquares, to actually declare a sumOfSquares function object, I’ll need to introduce lambda. In short:
sumOfSquares = lambda a, b: sum(a, b, square)
sumOfCubes = lambda a, b: sum(a, b, cube)
Lambda creates objects known as “anonymous functions,” which can be assigned to a variable name like sumOfSquares. Our new version of sumOfSquares is completely equivalent to the one that we first defined at the top.
-
http://www.cprogramming.com/ Alex Alex
