functionsscopingand abstraction def findroot(xpowerepsilon)"""assumes and epsilon int or floatpower an intepsilon power > returns float such that **power is within epsilon of if such float does not existit returns none""if and power% = return none low min(- xhigh max( xans (high low)/ while abs(ans**power >epsilonif ans**power xlow ans elsehigh ans ans (high low)/ return ans def testfindroot()epsilon for in ( - - - )for power in range( )print 'testing str( +and power str(powerresult findroot(xpowerepsilonif result =noneprint no rootelseprint 'result**power'~=' figure finding an approximation to root specification of function defines contract between the implementer of function and those who will be writing programs that use the function we will refer to the users of function as its clients this contract can be thought of as containing two parts assumptionsthese describe conditions that must be met by clients of the function typicallythey describe constraints on the actual parameters almost alwaysthey specify the acceptable set of types for each parameterand not infrequently some constraints on the value of one or more of the parameters for examplethe first two lines of the docstring of findroot describe the assumptions that must be satisfied by clients of findroot guaranteesthese describe conditions that must be met by the functionprovided that it has been called in way that satisfies the assumptions the last two lines of the docstring of findroot describe the guarantees that the implementation of the function must meet functions are way of creating computational elements that we can think of as primitives just as we have the built-in functions max and abswe would like to have the equivalent of built-in function for finding roots and for many other complex operations functions facilitate this by providing decomposition and abstraction