Today: tuples, dict.items() output pattern, lambda, map, one-liners
Ever notice how each new type has a char that marks it literal form in the code:
For more detail see guide Python Tuples
>>> t = ('a', 13, 42) >>> t[0] 'a' >>> t[1] 13 >>> t[2] 42 >>> len(t) 3 >>> t[0] = 'b' TypeError: 'tuple' object does not support item assignment
It's possible to omit the parenthesis when writing a tuple. We will not do this in CS106A code, but you can write it if you like and it is allowed under PEP8. We will write our code more spelled-out, showing explicitly when creating a tuple.
>>> t = 1, 4 # This works >>> t (1, 4) >>> t = (4, 5) # I prefer it spelled out like this >>> t # PEP8 says parenthesis optional (4, 5)
Here is a neat sort of trick you can do with a tuple. This is a shortcut for the use of =
, assigning multiple variables in one step. This is just a little trick, not something you need to use.
>>> (x, y) = (3, 4) >>> x 3 >>> y 4
>>> cities = [('tx', 'houston'), ('ca', 'palo alto'), ('ca', 'san jose'), ('tx', 'austin'), ('ca', 'aardvark')] >>> >>> sorted(cities) [('ca', 'aardvark'), ('ca', 'palo alto'), ('ca', 'san jose'), ('tx', 'austin'), ('tx', 'houston')] >>> >>> sorted(cities, reverse=True) [('tx', 'houston'), ('tx', 'austin'), ('ca', 'san jose'), ('ca', 'palo alto'), ('ca', 'aardvark')]
Say we have a dict loaded up with data
>>> d = {'a': 'alpha', 'g': 'gamma', 'b': 'beta'}
Here is the dict-print code we used before. This is a fine, standard pattern you can continue to use. But we are going to look at another way.
>>> for key in sorted(d.keys()): ... print(key, d[key]) ... a alpha b beta g gamma
keys() values() items()
>>> d = {'a': 'alpha', 'g': 'gamma', 'b': 'beta'} >>> >>> d.keys() dict_keys(['a', 'g', 'b']) >>> sorted(d.keys()) ['a', 'b', 'g'] >>> >>> d.values() dict_values(['alpha', 'gamma', 'beta']) >>>
dict.items()
>>> d = {'a': 'alpha', 'g': 'gamma', 'b': 'beta'} >>> >>> d.items() # (key, value) tuples - all the data dict_items([('a', 'alpha'), ('g', 'gamma'), ('b', 'beta')]) >>>
sorted(d.items())
Recall that d.items()
is a list of len-2 (key, value) tuples in random order:
>>> d.items() # random order [('a', 'alpha'), ('g', 'gamma'), ('b', 'beta')]
Since sorting of tuples goes by [0]
first, and [0]
here is the key, the len-2 tuples are in effect sorted by key:
>>> sorted(d.items()) # sorted by key [('a', 'alpha'), ('b', 'beta'), ('g', 'gamma')]
So it just sorts by the key first. The sorting in this case just uses the key in each tuple, [0]
, never needing to look at [1]
, since the key values are all different.
>>> for item in sorted(d.items()): ... print(item[0], item[1]) ... a alpha b beta g gamma
Recall the shortcut
>>> (a, b) = (6, 7) >>> a 6 >>> b 7
Can use a similar shortcut inside a for loop. Since we are looping over tuples len-2, can specify two variables, and the loop unpacks each tuple into the variables, here key and value:
>>> for key, value in sorted(d.items()): ... print(key, value) ... a alpha b beta g gamma
The above phrase is the second way to do dict output, using .items().
It's handy that the .items() gets all the data, so and we don't need to look up the value in the loop. Also it's nice that the key and value are unpacked into the variables in the loop. This is just a shortcut.
Look at the wordcount.py example - both the sorted(d.keys()) and sorted(d.items()) phrases are shown for printing out a dict.
Map - a short way to transform a list - handy, but not super important
Lambda - an important way to package some code. Today we'll use map() to explore how lambda works
Lambda code is dense. Another way of saying that it is powerful. Sometimes you feel powerful with computer code because the code you write is long. Sometimes you feel even a little more powerful, because the code you write is short!
There is something satisfying about solving a real problem with 1 line of code. The 1-liner code is so dense, we'll will write it a little more deliberately. See how this works below!
Consider the following "double" def. What does this provide to the rest of the program?
def double n: return n * 2
The def sets up the name of the function, and associates it with that body of code. Later line can refer to this function by name. The drawing below shows a form of this - the name "double" now points to this black-box of code that anybody can call.
Answer: takes in one parameter value. Returns one value. The function name "double" points to the double code, printed as "0x7fe2caad0430" below, the address in memory where they code starts.
>>> # Normally don't def a function in the interpreter. >>> # But it works for little demos like this. >>> >>> def double(n): ... return n * 2 ... >>> >>> double(10) 20 >>> double(144) 288 >>> >>> double <function double at 0x7fe2caad0430> >>>
A visual of what map() does
map(double, [1, 2, 3, 4, 5]) -> [2, 4, 6, 8, 10]
>>> # We have a "double" def >>> def double(n): ... return n * 2 ... >>> >>> map(double, [1, 2, 3, 4, 5]) <map object at 0x7f9a25969910> # why we need list() >>> >>> list(map(double, [1, 2, 3, 4, 5])) [2, 4, 6, 8, 10] >>> >>> list(map(double, [3, -1, 10])) [6, -2, 20] >>> >>> list(map(double, range(20))) [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38] >>>
Create a minus() function that takes in n, returns -n.
>>> def minus(n): ... return -1 * n ... >>> list(map(minus, [1, 2, 3, 4])) [-1, -2, -3, -4] >>> >>> list(map(minus, range(20))) [0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, -19] >>>
Say we have an exclaim(s)
function that takes in a string and returns it uppercase with an exclamation mark at the end. Use map to run exclaim() over a list of strings.
>>> def exclaim(s): ... return s.upper() + '!' ... >>> >>> list(map(exclaim, ['hi', 'woot', 'donut'])) ['HI!', 'WOOT!', 'DONUT!'] >>> >>> list(map(exclaim, ['meh'])) ['MEH!']
The map() function saves us some boilerplate - if we have a function, it takes care of the not too difficult job or running it over a list of inputs, giving us a list of outputs. This is a first example of passing a function in to another function as a parameter, which turns out to be an important advanced technique.
Enter the Lambda
Here is a lambda that takes in a number, returns double that number
lambda n: n * 2
It's like the lambda just defines the black box code, not bothering with giving it name.
Want to double a bunch of numbers? Instead of a separate def, write the lambda inside the map() like this:
>>> list(map(lambda n: n * 2, [1, 2, 3, 4, 5])) [2, 4, 6, 8, 10]
Write the word "lambda"
Do these in interpreter >>>. Just hit the up-arrow to change the body of the lambda.
>>> nums = [1, 2, 3, 4] >>> >>> # n * 10 >>> list(map(lambda n: n * 10, nums)) [10, 20, 30, 40] >>> >>> # n * -1 >>> list(map(lambda n: n * -1, nums)) [-1, -2, -3, -4] >>> >>> # 100 - n >>> list(map(lambda n: 100 - n, nums)) [99, 98, 97, 96] >>> >>>
Have a list of strings. Map a lambda over this list. What is the parameter to the lambda? One string. Whatever the lambda returns, that's what makes up the list of results.
1. Compute list of lowercase string forms
2. Compute list of first char of each string
>>> strs = ['Banana', 'apple', 'Zebra', 'coffee', 'Donut'] >>> >>> # 1. Lowercase form >>> list(map(lambda s: s.lower(), strs)) ['banana', 'apple', 'zebra', 'coffee', 'donut'] >>> >>> # 2. First char >>> list(map(lambda s: s[0], strs)) ['B', 'a', 'Z', 'c', 'D'] >>>
One liners!
> shout()
These are true one-liner exercises. We'll do a few of them in class, and you can look at the others in the lambda1 section on the server.
Solve these with a 1-line call to map() for each. Do not call list(), that was needed in the interpreter, but here just map() works.
> exercises
For reference, here is the syntax for our "double" example:
map(lambda n: n * 2, [1, 2, 3, 4, 5])
diff21() is int exercise, the others are string
> diff21
> first2x
> first_up