include "../_i/1.h"; ?>
http://www.flickr.com/photos/alstonfamily/2237347597
One try:
def maximum(numbers): """ Return the largest element in a list. """ high = 0 for x in numbers: if x > high: high = x return high
But this doesn't work in every case! How is it broken? How can it be fixed?
>>> from utils import maximum >>> maximum([-2, -4, -1]) 0
def maximum(numbers): """ Return the largest element in a list. """ high = numbers[0] for x in numbers: if x > high: high = x return high
Now we can handle an all-negative list, too. But we start with the first element of the list, and then the first time through the loop we compare that to itself. Is that really necessary?
def maximum(numbers): """ Return the largest element in a list. """ high = numbers[0] for x in numbers[1:]: if x > high: high = x return high
Clever. But: we are now copying the entire list minus one element, which could be very expensive if we are passed a large list. Probably better to do one extra comparison than to copy the entire list. But I digress...
def maximum(numbers): """ Return the largest element in a list. """ numbers.sort() return numbers[-1]
Lists have a built-in .sort()
method! But...
Function arguments in Python are passed by reference, not by value. If an argument is mutable (strings and numbers are not, lists and dictionaries are), if you change it inside the function the change will appear outside the function, too:
>>> from utils import maximum >>> my_list = [2, 1, 7, 4, 3] >>> maximum(my_list) 7 >>> my_list [1, 2, 3, 4, 7]
This might surprise someone calling your function!
def maximum(numbers): """ Return the largest element in a list. """ return sorted(numbers)[-1]
sorted()
returns a sorted version of the list, it
doesn't modify the list you pass to it.
All that work... and it's actually already built-in to Python:
>>> my_list = [2, 1, 7, 4, 3] >>> max(my_list) 7
def oldest(people): """ Expects a dictionary of people's names -> ages. Returns the name of the oldest person. """ high = None oldest = None for name in people: age = people[name] if high is None or age > high: high = age oldest = name return oldest
This is subtly broken, too; or at least under-specified, because the assignment itself was not clearly specified. How?
>>> from utils import oldest >>> people = {'Jeffrey': 23, 'Aloysius': 37, 'Selena': 37} >>> oldest(people) Aloysius
def oldest(people): """ Expects a dictionary of people's names -> ages. Returns the name of the oldest person. """ high = None oldests = [] for name in people: age = people[name] if high is None or age > high: high = age oldests = [name] elif age == high: oldests.append(name) return oldests
def squared(numbers): """ Expects a list of numbers. Returns a corresponding list with each element squared. """ return [x**2 for x in numbers]
Pretty simple.
http://www.flickr.com/photos/ctorok/358096814/
>>> def times2(x): print x*2 >>> a = times2(7) 14 >>> print a None >>> def times2(x): return x*2 >>> a = times2(7) >>> print a 14
In web apps, we never use print (except maybe debugging). Nobody's looking at the server screen. A function that generates some value should return that value so the rest of your program can use it.
for elem in my_list: ... do something with elem ... for i in range(len(mylist)): elem = mylist[i] ... do something with elem ...
In Python, you very rarely want the latter. Why? The former is cleaner, easier to read, and works with a wider variety of "iterable" objects. In those rare cases when you really need the counter variable, do this:
for i, elem in enumerate(mylist): ... do something with i and elem ...
Python lets you do this. But it's a bad idea, because it makes things confusing. "Is 'list' here the built-in type 'list', or some other variable 'list'"?
>>> print list <type 'list'> >>> def some_func(list): ... print list >>> some_func('blah') 'blah'
Some names of builtin types: list, dict, str,
bool
. Also None
. Also all the functions you see
when you type dir(__builtins__)
.
Don't hesitate to reuse your own code! That's what functions are for; to allow you to set apart a logical chunk of code and reuse it. Don't reimplement something if you've already written a function to do it.
Or if someone else has.
(note to self: stop assigning homework exercises to reimplement builtin functions, then.)
Function and variable names should be lowercase, with underscores
as needed for readability. Module (file) names lowercase, with
underscores used sparingly if at all. my_list, utils.py
&c.
Avoid variables named "l", "O", or "I", because you're just asking for trouble.
For all the gory details, read PEP 8.
Why bother? Readability and maintainability count (code is read far more often than it is written). These are the conventions other Python programmers will expect.
include "../_i/3.h" ?>