debuggingtestingand profiling what kind of hypothesis might we think upwellit could initially be as simple as the suspicion that particular function or method is returning erroneous data when certain input data and options are used thenif this hypothesis proves correctwe can refine it to be more specific--for exampleidentifying particular statement or suite in the function that we think is doing the wrong computation in certain cases to test our hypothesis we need to check the arguments that the function receives and the values of its local variables and the return valueimmediately before it returns we can then run the program with data that we know produces errors and check the suspect function if the arguments coming into the function are not what we expectthen the problem is likely to be further up the call stackso we would now begin the process againthis time suspecting the function that calls the one we have been looking at but if all the incoming arguments are always validthen we must look at the local variables and the return value if these are always correct then we need to come up with new hypothesissince the suspect function is behaving correctly but if the return value is wrongthen we know that we must investigate the function further in practicehow do we conduct an experimentthat ishow do we test the hypothesis that particular function is misbehavingone way to start is to "executethe function mentally--this is possible for many small functions and for larger ones with practiceand has the additional benefit that it familiarizes us with the function' behavior at bestthis can lead to an improved or more specific hypothesis--for examplethat particular statement or suite is the site of the problem but to conduct an experiment properly we must instrument the program so that we can see what is going on when the suspect function is called there are two ways to instrument program--intrusivelyby inserting print(statementsor (usuallynon-intrusivelyby using debugger both approaches are used to achieve the same end and both are validbut some programmers have strong preference for one or the other we'll briefly describe both approachesstarting with the use of print(statements when using print(statementswe can start by putting print(statement right at the beginning of the function and have it print the function' arguments thenjust before the (or eachreturn statement (or at the end of the function if there is no return statement)add print(locals()"\ "the builtin locals(function returns dictionary whose keys are the names of the local variables and whose values are the variablesvalues we can of course simply print the variables we are specifically interested in instead notice that we added an extra newline--we should also do this in the first print(statement so that blank line appears between each set of variables to aid clarity (an alternative to inserting print(statements directly is to use some kind of logging decorator such as the one we created in