Transcript for:
CS50's Introduction to Programming with Python: Debugging

so [Music] [Music] all right this is cs50s introduction to programming with python my name is david malin and this is a look at debugging odds are by now you've written quite a bit of code and within that code is at least one maybe even more bugs that is mistakes that you accidentally introduced to your code now maybe your code doesn't even run at all and you have some form of syntax error or maybe you've gotten past that hurdle and you just have one or more logical bugs so to speak whereby when you run your code it doesn't produce the output that you actually intended so it's not quite correct there are mistakes there in and how do you go about then solving those problems well if you can't quite wrap your mind around what's going wrong by just reading with your own human eyes your own code from top to bottom left to right and you don't have for instance a teacher a friend a colleague a rubber duck to help you reason through what might be wrong in your code what kind of tools do we actually have for chasing down bugs in code and ultimately fixing them well already we actually have some tools at our disposal and for instance let me propose that we build something like this in code so pictured here is mario from super mario brothers the original nintendo game jumping over a pyramid of sorts and that period is implemented with these bricks of sorts let's go ahead and create a textual version thereof whereby we use maybe hash symbols simple hashes to represent each of these bricks and therefore the goal in printing out a pyramid textually that resembles that of mario here would be to print out one hash and then two hashes and then three hashes and perhaps more if the pyramid itself is higher well let me propose that if i open up vs code here and in advance i've created a file called mario.pi let me propose that this is my intended solution to this problem let's go ahead and walk through what's what's here i first at the top of my file have a main function defined inside of which is the second line of code that calls input asking the user for the height of this pyramid immediately the return value of input is passed to the input of int so as to convert that textual input presumably to the corresponding integer and then i'm storing on the left-hand side of that equal sign the value that the user typed in be it one two three or anything else and then i'm using that variable as an input to a function that's apparently called pyramid so that i can ultimately print out a pyramid of that height all right well what is this pyramid function well it looks like on this line six that the pyramid function expects one argument called n and presumably for number and how am i using that number well inside of this function i have a for loop that's going to iterate it would seem n times and this is indeed our common paradigm doing 4i in the range of n allows us to iterate from 0 on up and then that innermost line of code is just going to go ahead and print out some number of hashes and recall this trick whereby we're using the multiplication operator but really just to automatically concatenate one or more of these hashes together so hopefully the net effect of this program once we actually run it per these final two lines and main is invoked and then pyramid is invoked is that we'll get a pyramid of the corresponding height but suppose now that i very enthusiastically went about trying to run this program and so i went to my terminal window and ran mar python of mario.pi and then i went ahead and proposed a height of three the goal being to have one hash two hashes three hashes so that the total pyramid is of height three i'm a little disappointed already to see that ah it's not quite correct this output i seem to have a pyramid really of height two because there's a blank line and then a single hash and then two hashes but again what i wanted was one hash then two hashes then three hashes forming a pyramid that's in total of height three now you might have an immediate instinct as to how to fix this problem and indeed relatively speaking this isn't the most complicated program at least if you're a few weeks into learning and writing code in python but suppose that it's just not obvious to me or this is representative of an even more complicated problem down the road and so i'd really like to start figuring out systematically how to solve this particular bug well what's one tool in my toolkit well let me propose first that i do this let me clear my terminal window to get rid of the output from before and let me propose that it might be helpful for me to maybe figure out if maybe i is wrong right i is my variable in this for loop that's responsible for printing out presumably one hash then two hashes then three hashes and so forth so maybe just to check my understanding here i should maybe why don't i temporarily just print out i in addition to these hashes just so that i can make sure that i is what i expect next to the appropriate number of hashes which is to say print itself the function we've been using now for quite some time it's a very reasonable effective tool for debugging at least in some cases it's a nice way to quickly and dirtily kind of see what's going on inside of your code well let me do this in addition to printing out that number of hashes let me also print out the value of i but rather than print out a new line which i think is going to completely mess up the pyramid let me just end the line with a single space just to kind of push the cursor over to the right so that my pyramid is printed to the right of all of these integers all right let me go down to my terminal window again and run python of mario.pi enter i'm going to again type in 3 for the height and now i see essentially the same output but i've prepended so to speak to each line the value of i and now maybe it makes a little more sense to me now maybe the proverbial light bulb just went off over my head because oh the reason i'm seeing a blank line and then only one and only two hashes on the screen instead of one two and three respectively is because i of course now i remember starts from zero certainly when doing a for loop like the one i have here on line seven so how do i go about fixing this well i think instinctively i could just do this let me go ahead and remove the previous print indeed when using print to debug your code it's usually temporary so i should now undo that change because i don't want those numbers to appear ultimately in my program's output let me go ahead now and print out okay i don't want to print out zero hashes and then one and then two i want to print out one more than the current value of i and i bet there's a bunch of ways i can solve this but i think the easiest way might be this let me go ahead and in parentheses do i plus one so that what i'm really doing is multiplying the single hash by i plus one so it instead of being zero one and two hashes respectively now it's one two 3. and i've parenthesized it just to make clear to myself that indeed the math is going to happen first just like in math class inside of the parentheses and then i'm going to use that total value for the concatenation of all of those hashes all right let me go ahead now back to my terminal window clearing it running python of mario.pi once more let's again type in a height of three and now i have the intended pyramid so a minor bug if you will certainly if you're several weeks into learning python already that kind of bug might have jumped out at you pretty quickly but that's not always going to be the case and so print is the first of your friends when it comes to debugging your code using print you can temporarily but pretty easily just display the values of variables or other things in your program just so you can help see what the computer sees underneath the hood so to speak but it turns out there's more powerful tools and print can start to get a little tedious especially if you're adding a print up here and up here and up here and appearing all over the place in more complicated programs because then you have to clean up a whole mess that you've made and you might have put the print in not the right location and you have to remember what output is coming from one print so eventually print is not so much your friend and we need better tools than that so let me go ahead and clear my terminal window again let me undo these changes so that i again have the same bug where i'm now printing out i number of hashes so 0 1 and 2 again and let me propose that we use another tool that comes with a lot of programming environments nowadays vs code included indeed typically i've hidden the so-called activity bar to the left hand side here of vs code but i've revealed it today so that we can see some of the functionality that actually comes with vs code and other text editors and other ides integrated development environments often come with built-in debuggers and indeed a debugger is a special type of program whose purpose in life is to do just that to help you debug your program it doesn't necessarily solve the problems for you so it's perhaps a bit of a misnomer but it helps you it empowers you to solve bugs yourself and eliminate them more methodically than maybe print alone would allow so i'm going to do this first i'm going to introduce this notion of what's called generally a break point a break point is simply a mechanism when using a text editor or an ide that allows you to specify on what line or what lines of code do you want to pause or break execution of the program just so you can start poking around at that line of code in other words if i keep running mario.pi in my terminal window it pretty much runs from top to bottom left to right again and again pausing of course for my own human input but it's so darn fast python that i can't really see what's happening on each individual line of code so let me go back to vs code and this time set a breakpoint wouldn't it be nice if i could pump the brakes so to speak and slow down the execution of my program so that i can tell the computer when i the human i'm ready to step step step through each of my lines of code so it turns out that to the left of the line numbers here in vs code and this is a popular approach in other programs as well notice if you hover over to the left of a line number it becomes a grayed out form of red and if you click on it once it becomes really red and what that indicates is that i've set one of these things called a breakpoint i've indicated to vs code in this case that i want it to break that is pause execution of my code just before main is called and i can actually set it on almost any of these lines of code but i'm starting at the very bottom one because of course that's the line of code that we know is going to kick off the whole process of running my code but it's going to allow me therefore to step through any and all of the specific lines they're in so let's go ahead and do this but now i'm not going to go ahead and just run python of mario.pi i need to actually run the debugger and the debugger in vs code is pretty smart to figure out exactly what i want to run and you can even configure it to be even more customized i'm going to go ahead and perhaps aptly click on this icon here aka run in debug and it's the little play icon with what appears to be an actual bug on it and when i click that this additional panel opens up in vs code and it's a big button there is called run and debug now i could follow more of the directions and customize it further but i'm just going to go ahead and click run in debug and using some default settings that i might have specified earlier to it's going to run my program but pause it on this line here notice that in yellow on line 12 that's where i set the break point and the yellow highlight of line 12 means that line of code has not yet executed but it's about to be executed if and when i am ready there's a bit of noise or messy output in my terminal window potentially but that's just part of the debugging process in my terminal window eventually well i see that same prompt for height but i don't yet because i'm not at that line of code now let me draw your attention to all of these icons at the top of the screen the first of these which looks like a play button with a line to the left of it is this continue button if i click that button the breakpoint is going to be left behind and my code's just going to continue on to the end of the program that's probably not what i want in this case because i actually do want to step through it line by line there's this next icon here an arrow going over a single dot that's the step over command this would allow me to step over this line 12 it will execute it but that's it it's not going to step into that function so that i can go line by line through main or in turn pyramid either the one i really want to use now is this one in the middle step into and this is the line pointing down at the dot which is a symbol that indicates that if i click this button in a moment i'm going to step into line 12 that is i'm going to step inside of the main function and from there i can continue to step by step walk through my code so watch what happens on the yellow on the screen here when i click step into like this you'll see that now line 12 has begun executing but when we step into that function notice now that the debugger has broken or paused on line two line two has not yet executed but as soon as i step over this one i think we're gonna start to see some results and i was careful there to stay to say step over instead of step into y well notice on this line of code two there's two functions input and int and i didn't implement either of those and allow me to propose that the people who invented python probably implemented input and int correctly so there's really no point in my stepping into their functions or even trying to i really should only be stepping into my own functions but i do want line two to execute but let me call your attention to this at the top left of vs code now there is under the run and debug panel some mention of variables both locals and globals and there's nothing under locals at the moment because at this moment before line two has been executed no variables actually yet exist in a moment once i do execute this line of code and step over it well a variable called height should exist so let's try that i'm not going to click step into i'm going to click step over but that will not ignore the line of code it will execute it but not dive into it if you will once i click step over notice that the line is no longer highlighted because execution hasn't broken or paused yet notice in my terminal window despite the output from earlier i'm being prompted for the actual height of the pyramid so this part is still interactive let me go ahead and type three and hit enter and now we'll see what's happened at the top of the screen line two has just executed the height variable now exists and indeed if you look up here you'll see in the debugger a graphical summary of all or in this case the one variable that now exists and better still you see the value of that variable now that's not that helpful at the moment because i'm pretty sure the height is as the user typed in so there's no off by one error or any bug there i think then the bug is probably inside of my pyramid function so here i don't want to click step over because that's going to execute pyramid and not allow me a chance to step through each of its lines i'm going to again this time because it's my function step into the pyramid function once i do that now it's line 7 that's highlighted because i've stepped into the pyramid function notice that the panel up here is changed the local variable that is the fun the variables that exist local to the pyramid function are indeed n because n was the argument that was passed in with a value of three i does not yet exist because line seven has not yet executed but here comes my for loop and here's where it's going to be interesting to step over and step over a few times i don't want to step into because the range function again was invented by someone other than me and let's just trust that it's correct so let's step over this line thereby executing it but watch the top left-hand corner of vs code let's step over it once and now notice not only does n equal three now there's another local variable called i that equals zero and what am i about to do on line eight well in a moment i'm going to click step over again because i'm going to trust that print is correct so i don't need to step into print but watch what happens now in my terminal window down here no pyramid no bricks have been printed but as soon as i step over line eight thereby executing it we see the first of my wait a minute i'm not seeing an actual brick if you notice the cursor did move down and effectively a blank line was printed and now there's an opportunity for that light bulb again to go off wait a minute i saw the cursor move it printed something but it's really nothing it's no bricks oh this is where now i might realize this is why my program is flawed because when i equals 0 i'm apparently printing zero bricks now hopefully i understand if not no big deal i can continue stepping over or stepping into each of my lines of code i can click the big stop icon or i can restart the whole process sometimes it might not be obvious the first time around and sometimes you might want to unset or reset a different breakpoint so as to figure out what's actually going on it's just part of the process of debugging for now that i figured it out i'm going to go ahead and just continue my program because i know that it's flawed but i now know what the problem is let me go ahead and close this panel over here i'm going to get rid of the break point because i've now in my mind at least solve this problem i'm going to clear my terminal window i'm going to go in and just logically add what i think is the solution to this problem by doing i plus 1 in parentheses again i'm going to now run one final time mario pi with python i'm going to again type in height of 3 and there it is my pyramid of height three so ultimately what are the tools in your toolkit well certainly print is something that you can always reach for not just in python but so many other languages as well or some equivalent thereof but sometimes once your programs get sufficiently complicated sufficiently sophisticated or heck maybe it's someone else's code that you yourself didn't write and therefore you would especially benefit from stepping through it line by line stepping into functions of interest a debugger like that that comes with vs code is going to be your new best friend