1 00:00:08,040 --> 00:00:12,790 Welcome back. You've already seen that a function is a useful way to 2 00:00:12,790 --> 00:00:16,990 abstract from a bit of code to something that has a name and has parameters. 3 00:00:16,990 --> 00:00:20,050 The parameters help to make the code more reusable. 4 00:00:20,050 --> 00:00:24,160 You pass in a different parameter value and get a different result and the name 5 00:00:24,160 --> 00:00:27,940 makes it so that you can refer to the whole action of the function with a single name. 6 00:00:27,940 --> 00:00:30,955 It makes your code easier to read and understand. 7 00:00:30,955 --> 00:00:35,525 In this video, we're going to carry the abstraction process one step further. 8 00:00:35,525 --> 00:00:39,760 We can decompose what a function does into a set of actions, 9 00:00:39,760 --> 00:00:43,180 and some of those actions may be implemented in other functions, 10 00:00:43,180 --> 00:00:46,295 and we'll just invoke those other named functions. 11 00:00:46,295 --> 00:00:49,340 So in other words, inside of a functions code, 12 00:00:49,340 --> 00:00:51,940 we're going to invoke another function. 13 00:00:52,130 --> 00:01:01,155 For example, here we have a function sum_of_squares that takes three inputs x, y, and z. 14 00:01:01,155 --> 00:01:05,910 It takes the square of each one on lines 6, 7, 15 00:01:05,910 --> 00:01:11,225 and 8, and it adds them all up and returns the sum. 16 00:01:11,225 --> 00:01:15,484 When in order to get the square of each of those inputs, 17 00:01:15,484 --> 00:01:19,280 we invoke the square function which is defined up here. 18 00:01:19,280 --> 00:01:22,490 So, we're inside the function sum_of _squares, 19 00:01:22,490 --> 00:01:25,145 we're invoking the function square. 20 00:01:25,145 --> 00:01:29,060 Let's see that execute in slow motion. 21 00:01:32,210 --> 00:01:36,190 So, we first we define the two functions, 22 00:01:36,680 --> 00:01:39,690 and then we set values for a, 23 00:01:39,690 --> 00:01:42,180 b, and c, those all get set in 24 00:01:42,180 --> 00:01:47,650 the global frame and now we're ready to invoke sum_of_squares. 25 00:01:47,650 --> 00:01:55,615 So, we get a new stack frame and we get the values for the parameter names. 26 00:01:55,615 --> 00:02:01,370 So, x gets whatever a used to be bound to or still is bound to, 27 00:02:01,370 --> 00:02:04,010 so that minus five came from there. 28 00:02:04,010 --> 00:02:08,405 Y gets the value that b had, which was two. 29 00:02:08,405 --> 00:02:12,450 Z gets the value that c had, which is 10. 30 00:02:14,630 --> 00:02:17,460 Now, when we execute sum_of_squares, 31 00:02:17,460 --> 00:02:19,590 we get to line six, 32 00:02:19,590 --> 00:02:24,585 and on line six, we are invoking the square function. 33 00:02:24,585 --> 00:02:28,345 We're invoking that inside of the definition of sum_of _squares. 34 00:02:28,345 --> 00:02:31,345 So, when we invoke it, we get another stack frame. 35 00:02:31,345 --> 00:02:37,340 So, this is going to give us a local namespace for variables for the execution of square. 36 00:02:37,700 --> 00:02:42,625 It's also interesting to note that we have a variable x, 37 00:02:42,625 --> 00:02:44,685 whose value is minus five. 38 00:02:44,685 --> 00:02:45,935 In sum of the squares, 39 00:02:45,935 --> 00:02:47,410 there's also an x, 40 00:02:47,410 --> 00:02:49,270 whose value is minus five, 41 00:02:49,270 --> 00:02:51,715 but these are different variables. 42 00:02:51,715 --> 00:02:54,650 So, we could change the value of 43 00:02:54,650 --> 00:02:59,465 x in square and that would not have an effect on sum of the squares. 44 00:02:59,465 --> 00:03:06,030 In fact, we will see that because we do a similar thing with the variable y. 45 00:03:06,710 --> 00:03:13,775 On line two we create a value for y in the square stack frame. 46 00:03:13,775 --> 00:03:19,410 So now y has the value 25. 47 00:03:19,960 --> 00:03:27,305 There's also a value for y in the sum_of_squares frame that it has a different value two, 48 00:03:27,305 --> 00:03:30,575 and we have not changed anything here. 49 00:03:30,575 --> 00:03:34,070 Once we continue the execution, 50 00:03:34,070 --> 00:03:38,705 we'll go forward the square stack frame is going to disappear. 51 00:03:38,705 --> 00:03:41,285 We're going to return the value 25, 52 00:03:41,285 --> 00:03:46,370 but the y in sum _of_squares is completely unaffected. 53 00:03:46,370 --> 00:03:48,834 That explains the mechanics. 54 00:03:48,834 --> 00:03:54,380 Now, let's try doing functional decomposition to write a little bit more useful function. 55 00:03:54,380 --> 00:03:56,450 Remember, from last week Wednesday, 56 00:03:56,450 --> 00:03:58,160 we've taught you about dictionaries. 57 00:03:58,160 --> 00:04:01,745 You had some code to accumulate a dictionary of counts. 58 00:04:01,745 --> 00:04:05,585 I've turned that into a function count_freqs, 59 00:04:05,585 --> 00:04:08,760 short for count frequencies. 60 00:04:12,610 --> 00:04:17,780 It takes one formal parameter st short for 61 00:04:17,780 --> 00:04:22,130 string to remind me that the input parameter is going to be a string, 62 00:04:22,130 --> 00:04:26,420 and it's going to count frequencies for whatever string is passed in. 63 00:04:26,420 --> 00:04:30,835 Now, the code should look a little bit familiar. 64 00:04:30,835 --> 00:04:34,910 From last week, we start by making an empty dictionary, 65 00:04:34,910 --> 00:04:38,540 we iterate through all of the characters in the string. 66 00:04:38,760 --> 00:04:42,770 If the character is not yet a key in the dictionary, 67 00:04:42,770 --> 00:04:45,010 meaning this is our first time seeing it, 68 00:04:45,010 --> 00:04:50,875 we add it as a key in the dictionary and we give it an initial value of zero. 69 00:04:50,875 --> 00:04:54,830 Then regardless of whether we've seen this character before or not, 70 00:04:54,830 --> 00:04:58,025 we're going to increment the counter that's associated with it. 71 00:04:58,025 --> 00:05:00,745 So, if this was the first time we saw it, 72 00:05:00,745 --> 00:05:04,055 it starts with a zero and now it's got one for its count. 73 00:05:04,055 --> 00:05:07,505 But if we've already seen this character say three times before, 74 00:05:07,505 --> 00:05:10,670 the count will get updated to be four. 75 00:05:11,720 --> 00:05:17,435 So, the new things here over what you saw last week or that we've turned 76 00:05:17,435 --> 00:05:19,910 the bit of code into a function 77 00:05:19,910 --> 00:05:23,660 and before you just saw how to do this with a particular string. 78 00:05:23,660 --> 00:05:26,270 Now, we're making it work for any string we've 79 00:05:26,270 --> 00:05:29,810 made the string b a formal parameter of the function. 80 00:05:29,810 --> 00:05:32,930 The other thing that's different is instead of printing 81 00:05:32,930 --> 00:05:35,720 out the result at the end or assigning it to a variable, 82 00:05:35,720 --> 00:05:39,260 we just return it and then whatever code is 83 00:05:39,260 --> 00:05:43,505 invoking count_freqs will decide what to do with the return value. 84 00:05:43,505 --> 00:05:47,100 Similarly, you had code last week, 85 00:05:47,100 --> 00:05:50,960 given a dictionary to find the best key in the dictionary, 86 00:05:50,960 --> 00:05:56,340 to find the key that had the maximum value associated with it. 87 00:05:56,810 --> 00:05:59,730 So again, I've turned that into a function, 88 00:05:59,730 --> 00:06:02,140 I called it best_key, 89 00:06:02,140 --> 00:06:05,180 and it will take any dictionary as an input. 90 00:06:05,180 --> 00:06:09,740 That dictionary should have keys and values where the values are 91 00:06:09,740 --> 00:06:14,940 numbers and it's going to return the key that has the highest value. 92 00:06:14,940 --> 00:06:19,915 Given both of these functions count_freqs and best_key, 93 00:06:19,915 --> 00:06:24,400 I can now compose a bigger function most_common_letter. 94 00:06:24,400 --> 00:06:27,170 So, it's going to take a string as an input, 95 00:06:27,170 --> 00:06:31,880 and just to distinguish it I've chosen to give it a different parameter name, 96 00:06:31,880 --> 00:06:33,860 I could have called it st just like I used for 97 00:06:33,860 --> 00:06:37,720 count_freqs but I decided to call it s here. 98 00:06:37,720 --> 00:06:39,600 We're doing this in two steps. 99 00:06:39,600 --> 00:06:43,515 In step one, we count the frequencies in s, 100 00:06:43,515 --> 00:06:45,090 which creates a dictionary, 101 00:06:45,090 --> 00:06:49,160 and I've assigned that to a variable called frequencies. 102 00:06:49,160 --> 00:06:56,555 I pass that dictionary into the best_key function and what I get back is one key, 103 00:06:56,555 --> 00:06:59,990 the key that has the highest value I return that and that should be 104 00:06:59,990 --> 00:07:05,340 the most common letter in our string s. So, 105 00:07:05,340 --> 00:07:08,405 let's run this and make sure that it actually works. 106 00:07:08,405 --> 00:07:14,185 Down at the bottom, I'm invoking most_common_letter on line 21, 107 00:07:14,185 --> 00:07:18,080 and I'm passing in a string that has a bunch of b's bunch of c's. 108 00:07:18,080 --> 00:07:21,890 As you can see that it's got more b's than any of the other letters, 109 00:07:21,890 --> 00:07:24,830 and what we should get as our output is just the letter 110 00:07:24,830 --> 00:07:28,300 b and sure enough that's what we get. 111 00:07:28,300 --> 00:07:34,200 If I change my string and give it a whole lot more c's, 112 00:07:35,410 --> 00:07:39,995 now when I run it I should get the letter c instead, 113 00:07:39,995 --> 00:07:42,420 and sure enough I do. 114 00:07:44,890 --> 00:07:49,280 Now, I want to described this as a composition process. 115 00:07:49,280 --> 00:07:55,590 Often though, you'll actually solve problems in the opposite order by decomposition. 116 00:07:55,940 --> 00:07:58,320 You might start by saying, "Hey, 117 00:07:58,320 --> 00:08:00,630 I want to find the most_common_letter." 118 00:08:00,630 --> 00:08:03,710 So, let's decompose that into first finding 119 00:08:03,710 --> 00:08:08,510 the frequencies of all the letters and then picking the one with the highest frequency. 120 00:08:08,510 --> 00:08:11,785 When I start that decomposition process, 121 00:08:11,785 --> 00:08:14,990 those functions may not exist yet but I just refer 122 00:08:14,990 --> 00:08:19,140 to them by name and then afterwards I find definitions for them. 123 00:08:20,350 --> 00:08:24,630 So really, how I wrote this code, 124 00:08:25,010 --> 00:08:28,485 I started by defining most_common_letter, 125 00:08:28,485 --> 00:08:31,110 and I referred to the functions count_freqs 126 00:08:31,110 --> 00:08:34,660 and best_key even though those functions didn't exist. 127 00:08:34,660 --> 00:08:38,540 Because I had given them names that made me know what they would do, 128 00:08:38,540 --> 00:08:42,525 I was able to write that function and have it be clear what it was going to 129 00:08:42,525 --> 00:08:47,700 do and then I had to go and fill in the other two functions. 130 00:08:49,270 --> 00:08:51,619 As a little aside, 131 00:08:51,619 --> 00:08:57,330 you may be wondering why it works to have on line 132 00:08:57,330 --> 00:09:03,750 two a reference to the count_freqs function which has not been defined yet, 133 00:09:03,750 --> 00:09:08,500 when we talk about executing Python code from top to bottom. 134 00:09:08,500 --> 00:09:12,170 So, we shouldn't be able to refer on line 135 00:09:12,170 --> 00:09:17,060 two to a function that isn't defined until line five. 136 00:09:17,060 --> 00:09:21,385 The reason we don't get an undefined variable error, 137 00:09:21,385 --> 00:09:26,920 is that even though on line two we're referring to count_freqs, 138 00:09:26,920 --> 00:09:29,665 we don't actually execute line two, 139 00:09:29,665 --> 00:09:34,925 until after we invoke on line 21 the most_common_letter function. 140 00:09:34,925 --> 00:09:41,170 So, by the time we actually execute line two count_freqs has been defined. 141 00:09:41,170 --> 00:09:43,660 If we were not inside a function definition, 142 00:09:43,660 --> 00:09:45,445 we really would have a problem. 143 00:09:45,445 --> 00:09:51,640 For example, if I say print of x and then x equals four, 144 00:09:51,640 --> 00:09:56,540 I will get an error because on line one x is not defined. 145 00:09:57,780 --> 00:10:03,910 The difference is that, inside a function, 146 00:10:03,910 --> 00:10:08,530 we're not actually going to refer on line five to count_freqs until line 147 00:10:08,530 --> 00:10:14,440 five executes and by that time the count_freqs function has been defined. 148 00:10:16,340 --> 00:10:22,515 So to summarize, functions can call other functions, it's called composition. 149 00:10:22,515 --> 00:10:25,720 You get multiple stack frames when that 150 00:10:25,720 --> 00:10:29,705 executes each one has its own namespace and its own local variables. 151 00:10:29,705 --> 00:10:31,910 As a problem-solving strategy, 152 00:10:31,910 --> 00:10:33,815 it's helpful to decompose, 153 00:10:33,815 --> 00:10:36,670 to find a function by referring to other functions that don't yet 154 00:10:36,670 --> 00:10:42,220 exist and then write those functions. See you next time.