Functions and libraries ----------------------- Functions are fun! There's a lot of vocabulary associated with functions, so this explanation sets out many of the terms which relate to them. A function is a piece of code (a set of instructions, a rule) which can act on some input to do something. Traditionally -- and always in mathematics -- we say that a function returns or yields a value. The inputs to a function, if there are any, are also called its arguments. Python functions are broader and more flexible than mathematical functions. The arguments to a Python function may be of any number and of any type; some may be optional. The return value may also be of any type (although it must be a single value) -- and it need not exist at all (in which case a special object value called None is deemed to have been returned; you can think of this as meaning "not applicable"). The biggest difference between mathematical functions and Python functions is that a Python function's return value need not depend solely on its inputs. It may also depend on anything else accessible to the function (e.g. the current time, the contents of files on disk, the data read from a network connection, a count of how many times a particular function has been called, the value of a variable defined elsewhere in the program, etc.). In addition, the function may, while executing, perform actions which have lasting effects. These are called "side effects" of using the function. In some languages, side effects from functions are not possible (although most languages eventually make concessions to the practical demands of programmers, who tend to want side effects to be possible). It's usually easier to understand and debug code which minimizes side effects, because functions without side effects are closer to the mathematical sense of "function". (In mathematics, when we use sin(x) to find out something about a triangle, we don't normally expect that the triangle will be changed in the process, or that a file on a disk will be deleted as a result.) But most programmers don't feel a moral compunction against producing side effects; sometimes they're the most natural way of expressing something. So in general, you call (or invoke) a function on its arguments, and obtain the return value; side effects may occur in the process. Functions that come with Python (a small sample) ------------------------------------------------ Python comes with many built-in functions. Here are a few of them, with brief explanations. abs returns the absolute value of a number chr converts an integer into an ASCII character -- so that chr(65) == "A" dir shows the functions or other names defined within a particular module or object; try calling it on various things and see what you get! divmod divmod(a,b) == (a/b, a%b) useful for certain mathematical operations, such as converting a number into binary eval tells what value a particular string would have if it were typed into the Python interpreter as code. For example, eval("2+2") == 4. filter uses a function to excerpt from a list all those elements for which some condition is true. filter(f, L) does something like new_list = [] for x in L: if f(x): new_list = new_list + [x] return new_list float converts a number to a floating-point (decimal) numerical type hex converts a number to a string which is the name of that number in hexadecimal input gives you eval(raw_input()) -- which can be risky because the user's input may contain syntax errors, or you might not want to interpret it as code! int converts a number to an integer (whole number) numerical type (rounding down for positive numbers, rounding up for negative numbers); see also math.ceil and math.floor isinstance isinstance(x,t) tells whether x is something of type t, assuming that t is a type object. len tells the number of elements in a sequence type (e.g. the number of items in a list, or the number of characters in a string) list given a sequence type, return a list containing the same elements as that sequence type (e.g. convert a string to a list, or a tuple to a list) -- try list("hello there") long converts a number to an arbitrary-precision long integer numerical type (like the int function, but gives a long integer instead of an integer; the maximum size of long integers is not limited, but they are otherwise identical to regular integers) map apply a function to each item in a list and return a new list containing all the return values. So map(f, L) does something like new_list = [] for x in L: new_list = new_list + [f(x)] return new_list max returns the largest of several items min returns the smallest of several items oct like the hex function, but returns the octal (base 8) representation of a number instead of hexadecimal (base 16) open opens a file (very important if you want to read or write files on disk in Python!) and returns a file object referring to that file. The basic form of open is either open("filename", "r") if you are going to read from a file, or open("filename", "w") if you are going to write to it. ord the inverse of the char function, tells you what the ASCII value of a particular character is. So ord("A") == 65. pow like the Python ** operator, raises a number to a power, so pow(2, 20) == 1048576. (This has another feature which is useful for people doing cryptography work -- it can also do a simultaneous % for efficient exponentiation modulo a constant. If you aren't doing crypto or number theory, you probably don't need pow.) range returns a list whose elements are equal to their indices (the first n numbers, starting with zero). Can also give slices from such a list (if called with two arguments) or count by something other than 1 (if called with three arguments). raw_input read a line of text from the standard input (normally the keyboard or terminal) and return it as a string, without an interpretation. (The line is considered to end when the user presses Enter, but the character corresponding to the Enter key is not included in the line.) reduce apply a two-argument function successively to "reduce" a long list to a single value. (This isn't used very often, but when you do find an application for it, it can be very elegant.) round round a floating point number to the nearest integer, but then return that as a floating point number. str convert pretty much anything (for example, a number) to a string. There is also a function called repr which can do this and may have slightly different behavior; for most types, the str function is probably what you want. tuple type returns the type object corresponding to the type of a particular object. One use for this is to find out whether two objects are the same type, via something like if type(x) == type(y): unichr returns the Unicode character whose value is given by a particular integer (like the chr function, but returns characters from the Unicode character set instead of the ASCII character set); this is used for work with international character sets. unicode translates a string into its Unicode representation (see unichr). xrange like range, but uses less memory; use this if you are dealing with a huge range and are having trouble with running out of memory. "This is slightly slower than range() but more memory efficient." zip "zips" sequences together, so that zip(a,b,c,d,...)[i][j] is element i from sequence j. One interesting thing is that Python functions are also objects which can be assigned to variables. So, for example, convert_character_to_ascii = ord print map(convert_character_to_ascii, "Good morning!") (You can't add or subtract or multiply functions, though.) In many other languages, functions are not objects and can't be assigned to variables, nor can they be used as arguments to other functions. Python is very flexible this way. Defining a function ------------------- You can write your own functions using the "def" statement. It looks like this: def function(argument, another_argument, yet_another_argument): body of function statements go here and possibly we will return a value Here is a simple example: def greet(person): print "Hello there,", person print "Pleased to meet you!" print print "What is your name?" you = raw_input() greet(you) What is the return value of greet(you)? It's None (and in this case, we don't even attempt to use it -- we say that we're using greet only for its effects and not for its value). The names of the arguments you specify when writing a function definition get turned into variables within the body of the function; each is "bound" with the corresponding value that was passed to it in the function call. def plus1(x): return x+1 y = 5 print plus1(y) (If you then try "print x", you'll see in action the only "scope rule" that we'll consider for the time being.) I'll give a few examples which will show some of the power of map, filter, zip, and defining your own functions. print max(map(len, ["This", "list", "contains", "strings", "of", "various", "lengths."])) f = filter(len, ["this", "", "list", "contains", "some", "", "", "empty", "strings", ""]) f[0] = "This" f[2:4] = ["doesn't", "contain", "any"] print f # hexadecimal chart map(hex,range(256)) # ASCII character set chart map(chr,range(256)) # joint hex-ASCII chart -- a little hard to read! zip(map(hex,range(256)), map(chr,range(256))) # is n odd? def odd(n): if n%2 == 1: return 1 else: return 0 # shorter version def odd(n): if n%2: return 1 else: return 0 # shortest version def odd(n): return n%2 # now try filter(odd, range(50)) # you can also do def even(n): return not odd(n) # this lets us do a lot of mathematics in a concise way def prime(n): divisible = 0 for i in range(2,n): if n % i == 0: divisible = 1 return not divisible # an alternative (showing that you can make functions faster # by returning immediately when you know the result; thanks to # George Moffitt for the suggestion): def prime(n): p = 1 for i in range(2,n): if n % i == 0: return 0 return 1 filter(prime, range(2,1000)) len(filter(prime, range(2,10000))) def add(a,b): return a+b reduce(add, range(10)) reduce(add, range(100)) reduce(add, filter(odd, range(100))) reduce(add, filter(prime, range(2,100))) filter(prime, range(2,10000))[:100] reduce(add, filter(prime, range(2,10000))[:100]) # This one is really neat -- why does it work? reduce(add, ["make", "no", "law", "respecting", "an", "establishment"]) print "Please enter your name, and I will tell you the total of the" print "ASCII characters in it." print reduce(add, map(ord, raw_input()) filter(even, filter(prime, range(2,1000))) I'm completely omitting mention of a function called lambda, mostly because I think lambda should have its own class to do it justice. You can look it up, if you're interested; it can make some of the above examples even more concise. Packages (using libraries and import) ------------------------------------- Your Python distribution comes with a significant amount of pre-written code, some of which is in Python and some of which is a Python interface to other code which is originally written in C. You can get ahold of this code by using the "import" statement. Usually, you use an import at the beginning of your program, so that someone reading your program knows which modules or packages you intend to use. In principle, an import can occur at any point. One form of import looks like import some_module which has the result of creating a new object called some_module, visible to your program. some_module may contain other objects, and normally many of those are functions which you can use. (Some of them might also be other things like object classes, types, strings, numerical constants...) Those can be referred to as some_module.object_name, and you'd want to look at the documentation for the particular module you're using to find out the names of the things it provides, and how they work. You can get a feel for "import" by trying these examples: pi = 3.1415926535 sin(pi) math.sin(pi) import math math.sin(pi) dir(math) sentence = "it is an ancient mariner and he stoppeth one of three" split(sentence) import string string.split(sentence) dir(string) The "math" and "string" packages are two which I use fairly often; math contains a lot of functions which are useful in doing math, and string contains a lot of functions which are useful in doing things with strings. (You can do _some_ things with strings without importing string; for example, you can find their length, concatenate them, and take slices. string just provides additional functions to do other things.) I also often use "sys" and "os". sys: This module provides access to some objects used or maintained by the interpreter and to functions that interact strongly with the interpreter. [One example is the command-line arguments, if you run your program from a command line, which are available as a list called sys.argv] os: OS routines for Mac, DOS, NT, or Posix depending on what system we're on. [This contains a lot of features like various things with files and directories and running other programs. When writing only for Unix, I use the "posix" module which gives access to more powerful and lower-level Unix features.] Any Python file can be used as a module just by putting it in the same directory as your program; then you can use it by running import foo if the file is called "foo.py". For example, Quote.py by Jon Corbet (the editor in chief of Linux Weekly News) contains Python code which uses Yahoo! Finance or some other web site to obtain a current stock quote for a particular symbol. Quote.py defines various functions; if you put it in the same directory as your program, and then do import Quote you'll immediately be able to use the function Quote.Lookup(), which is defined within Quote.py, and do something like Quote.Lookup("IBM").value to find out -- at any moment -- the current price of a share of IBM's stock. Now that you know this, you can write your own modules, and publish them, or re-use your own code in connection with other programs. If you don't like having to type the name of the module every time you use a function, you have two choices: First, you could assign something to a variable with a shorter name. look = Quote.Lookup Second, you can use the "from" form of input: from math import sin, cos, tan to get functions called sin, cos, and tan rather than math.sin, math.cos, and math.tan. The only problem with "from" is in keeping straight what came from where; in some cases, more than one module provides a function with a particular name! This wouldn't be a problem if you just imported those modules separately, because you can distinguish easily between foo.greatfunction() and bar.greatfunction(), but you want to be careful about a from import when the same name might be used by two different modules (including the "builtin" module of things automatically provided within Python). Well-organized code will use modules where appropriate, and, if it's complex enough, will provide modules of its own. The documentation for all the modules which come with Python is available on-line at http://www.python.org/doc/current/modindex.html There are a lot of them, and some provide very sophisticated features, so that you often don't have to write your own code if you can find an existing module which does part of what you want. On the other hand, the available Python modules are much fewer in number than the extremely impressive collection of Perl modules called CPAN: http://www.cpan.org/ Unfortunately, you can't currently use Perl modules within your Python programs (although you might want to look at the pyperl module if you're tempted!). You can get the Quote module from ftp://ftp.eklektix.com/pub/Quote/ and I've also provided the latest version I have at http://www.loyalty.org/~schoen/Quote.py The ability to use modules is extremely important. If you were an experienced Python programmer asking another experienced programmer "So, how do I write graphical user interfaces in Python?", you might get an answer as short use "Use [the module] Tkinter", with the implication that you need to read the documentation for the Tkinter module because it provides everything you need in order to write graphical programs. (This is true, although in order to use Tkinter in particular, we'll need to study object-oriented programming first.) Similarly, "How do I download documents from a web server?" might be answered with "urllib" (read the documentation for the urllib module), "How do I make network connections?" might be answered with "the socket module". Experienced programmers often expect other programmers to read documentation, and sometimes give terse advice. This is one reason that good documentation is so important; writing documentation for your own software is an important and often neglected skill. (Sometimes people have to hire technical writers just because the programmers writing something can't or won't document it.) Problems -------- Write a function which squares its argument. square(7) ---> 49 Write a function which tells you the first element of a list. first(["ne", "ought", "saue", "Tyber"]) ---> "ne" Write a function which tells you all the elements of a list except the first one. (The return value will itself be a list.) butfirst(["ne", "ought", "saue", "Tyber"]) ---> ["ought", "saue", "Tyber"] Write a function which concatenates two arguments. concat("foo", "bar") ---> "foobar" Without looking at my sample versions: Write reduce, using a for loop. (The specific way that reduce works is to start with the first element in the sequence it's given, and then apply the function it's given to that value and the next element, take the result and apply the function it's given to the result and the next element, and so on for each element in the list. reduce then returns the final value. So reduce(add, [1,2,3,4]) means add(add(add((1),2),3),4).) Write filter, using a for loop. Write map, using a for loop. Write a function that calculates a specified Fibonacci number. The Fibonacci numbers are 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ... Each one is the sum of the two Fibonacci numbers immediately previous. So your function should give fib(1) ---> 1 fib(2) ---> 1 fib(3) ---> 2 fib(4) ---> 5 fib(5) ---> 8 etc. Write a function which reverses the order of the characters in a string. reverse("Seth") ---> "hteS" reverse("EFF") ---> "FFE" reverse("make no law") ---> "wal on ekam" reverse("a canal, Panama") ---> "amanP ,lanac a" reverse("Anna") ---> "Anna" reverse(str(2**24)) ---> "61277761" Using that function, write a function which tells whether a string is a palindrome. palindrome("Anna") ---> 0 palindrome("anna") ---> 1 palindrome("redivider") ---> 1 palindrome("live evil") ---> 1 palindrome("This is no palindrome!") ---> 0 Can you make your function treat upper and lower case as equivalent? (Hint: there's a function in the string module called string.lower which might help.) Write a function which takes two arguments, x and y, and draws a rectangle out of plus signs, x across and y down: rectangle(5,1) ---> +++++ rectangle(3,3) ---> +++ +++ +++ rectangle(8,6) ---> ++++++++ ++++++++ ++++++++ ++++++++ ++++++++ ++++++++ Now change the function so that it takes another argument indicating which character to make the rectangle out of. Write a function which prints a triangle out of plus signs up to a specified number (given as an argument): triangle(4) ---> + ++ +++ ++++ Can you make your function center the triangle left-to-right, like this (now the argument tells how many lines to draw in the triangle)? centered_triangle(4) ----> + +++ +++++ +++++++ Write a function which (using Quote.py) takes as arguments a stock symbol and a number of shares, and returns the total value of that many shares of that stock. Now write a program which (using the function you just wrote) prompts the user for a stock symbol and number of shares, and then shows how much money they would be worth right now. Look at the documentation for string, math, and sys. Write a program which uses at least one function from each of these modules.