5.6 函数的功能
下面的第3行代码是一次函数调用,称为调用func函数
a=6b=func(a)print(b)函数的调用,,也可以在别的函数。例如A函数调用了B函数,然后又调用了A函数。现在我们要学会这样来“使用”函数。
看下面的题目:
定义一个函数,以一个整数为参数,返回该整数的绝对值。
这个函数能得到一个数字的绝对值,假设这个函数的名称是abs。
现在看下面的例子: 函数f(x)=x*x+5|x|+6和g(x)=x*x-|x|,x的类型是整数。 f和g两个函数都需要计算绝对值,我们可以使用已经写好的绝对值函数,来完成这两函数:
def abs(x): if x>0: return x else: return -xdef f(x): y=x*x+5*abs(x)+6 return ydef g(x): return x*x-abs(x)print(f(5))print(g(5))这其实就是函数最根本的作用:函数把功能单元抽象出来,需要的时候就可以使用。
abs(x)函数是得到x的绝对值,然后f调用了abs函数(第9行代码)。最后调用f函数,参数是5,打印出了最终计算结果。
如果把所有代码都到一个函数里面,那么就会复杂一点,同时会有重复的代码存在,这类冗余代码是要避免的。 例如f函数不用abs函数的话,那么就会变成这样:
def f(x): if x > 0: z = x else: z = -x y = x * x + 5 * z + 6 return ydef g(x): if x > 0: z = x else: z = -x return x * x-z第2到第4行代码就是计算x的绝对值,z的值就是x的绝对值。第11和14也是计算绝对值。这就是代码冗余。
代码冗余有什么坏处呢?
1.多余代码。
2.难以维护。需要修改的时候,就需要查找所有使用过的地方,然后修改!在这个例子里,绝对值的计算不会改变,但假如是一些复杂一点的逻辑。如果找到了更好的算法,需要替换,那么需要找到所有用过旧算法的代码,然后替换,不仅容易出错,还容易漏掉(想象一下某个代码片段在各处用了20次)。
其实,函数的最主要作用是:将复杂问题化成若干个简单函数,然后逐个解决。
下面我们来用这个分解问题的方法,来解决这个问题:
输入两个数字,求它们的最大公约数。
最大公约数是两个数字都能整除的最大数字。
解题思路是这样的:
1.i从2开始,定义max为1,max就是最终的最大公约数,num为两个数较小的数字
2.假如i小于等于num,进入第3步,否则算法结束,max就是最大公约数
3.判断i能不能被两个数整除,如果能,将i的值赋给max。进入第4步。
4.i加1,回到第2步
关于这些初值这么设置,是这样的原因:
i没必要从1开始,因为1必定能被任何整数整除,
max初值设定为1,如果max的值一直都没有改变,那么1就是两个数的最大公约数,所以max的初值不能随便设置(例如设为0是不行的)
num设置为两个数中较小的数,是为了减少循环次数。
可分解成下面这些函数:
min(a,b),返回a和b较小的那个数。
canBeDivide(a,b),a能被b整除,返回True,否则返回False
下面我们来实现它们,最终通过函数调用,完成最大公约数。
练习题
-
编程题1.定义函数min,两个数字为参数,返回较小的那个数。 (10分) [编程]2.定义函数max,输入两个整数,返回较大的那个数。 (10分) [编程]3.定义函数canBeDivide(x,y),参数是两个数字x和y,如果x能被y整除,那么返回True,否则返回False。 (10分) [编程]也就是x除以y,没有余数4.完成最小公倍数函数zxgbs,接收两个整型参数,返回两个参数的最小公倍数 (10分) [编程]解题思路是这样的:
(0) 将其中较大的数字赋给k,
(1)看k能不能整除两个数字,如果可以,那么到(2),否则到(3)
(2)这个k就是最小公倍数,直接返回i,算法结束。
(3)k加1,回到(1)。
那么首先这个循环,需要找到较大的那个数,可分解成下面这个函数:
整除关系的话,可以使用上一节的CanBeDivide函数(该函数定义的代码必须也复制过来)。
最小公倍数不会大于这两个数字的乘积,可用作循环结束的条件
最后不管是中间打断还是循环到结束,i都是最小公倍数,i是最终返回值5.完成上面两题后,看下面的伪代码 (10分) [编程]剩下的工作就比较简单了。最大公约数的这个算法的核心是穷举法,也就是每个i都拿来尝试,而细分的函数设计,能把大问题分解成小问题,便于问题的解决
根据伪代码完成此函数<code><div class='codeNewLine'><span class='keyword'>def</span> min(x,y):</div><div class='codeNewLine'> <span class="comments">#函数定义粘贴在此处</span></div><div class='codeNewLine'></div><div class='codeNewLine'></div><div class='codeNewLine'><span class='keyword'>def</span> canBeDivide(x,y):</div><div class='codeNewLine'> <span class="comments">#函数定义粘贴在此处</span></div><div class='codeNewLine'></div><div class='codeNewLine'></div><div class='codeNewLine'><span class='keyword'>def</span> zdgys(x,y):</div><div class='codeNewLine'> num=调用min函数,算出x和y较小的数</div><div class='codeNewLine'> max=1</div><div class='codeNewLine'> <span class='keyword'>for</span> i <span class='keyword'>in</span> <span class='pyFunction'>range</span>(2,num+1):</div><div class='codeNewLine'> <span class='keyword'>if</span>(调用canBeDivide判断x能被i整除并且调用canBeDivide判断y能被i整除):</div><div class='codeNewLine'> max=i</div><div class='codeNewLine'> <span class='keyword'>return</span> max</div><div class='codeNewLine'></div></code>6.定义函数isPrime,判断整型参数x是否素数 (10分) [编程]判断参数x是否是素数。
如果x是素数,返回True,如果不是则返回False。
算法:
(1)i=2,进入第2步
(2)如果i小于x,测试x能否被i整除,如果可以,返回false算法结束;如果不符合,进入第3步;
(3)i加1,如果i等于x,返回true算法结束;否则回到第2步
从2开始逐个去试,假如有某个数字可以整除,那么马上可以判断不是素数,可以立刻返回False,这就是第2步的逻辑;然而要判断是素数,必须整个循环走完,同时循环走完就能返回True,所以第3步里当i等于x的时候,说明i已经加到x都一直没找到,那么x是素数
我们有之前的整除判断函数canBeDivide,这里仍然可以使用7.最大公约数另外一个解题思路是这样的: (10分) [编程]i从两个数较小的数开始
(1)看i能不能被两个数字整除,如果可以,那么到(2),否则到(3)
(2)这个i就是最大公约数,直接返回i,算法结束。
(3)i减去1,回到(1)。
尝试下完成此算法,需要使用已经定义好的min和CanBeDivide函数:
注意函数return语句在这里的作用:相当于break,因为遇到return,整个函数计算就结束了,不需要用break停止循环再return<code><div class='codeNewLine'><span class='keyword'>def</span> min(x,y):</div><div class='codeNewLine'> <span class="comments">#函数定义粘贴在此处</span></div><div class='codeNewLine'></div><div class='codeNewLine'></div><div class='codeNewLine'><span class='keyword'>def</span> canBeDivide(x,y):</div><div class='codeNewLine'> <span class="comments">#函数定义粘贴在此处</span></div><div class='codeNewLine'></div><div class='codeNewLine'></div><div class='codeNewLine'><span class='keyword'>def</span> zdgys(x,y):</div><div class='codeNewLine'> num=调用min函数,算出x和y较小的数;</div><div class='codeNewLine'> <span class='keyword'>for</span> i <span class='keyword'>in</span> <span class='pyFunction'>range</span>(num,0,-1):</div><div class='codeNewLine'> <span class="comments">#i能整除x并且i能整除y,使用canBeDivide函数</span></div><div class='codeNewLine'> <span class='keyword'>if</span>(调用canBeDivide判断x能被i整除并且调用canBeDivide判断y能被i整除):</div><div class='codeNewLine'> <span class='keyword'>return</span> i</div><div class='codeNewLine'> <span class='keyword'>return</span> 1 <span class="comments">#最后到这里,说明前面的循环没有任何一个i可以整除,那么最大公约数就是1</span></div><div class='codeNewLine'></div></code>8.调用上一题的isPrime,打印100以内的素数 (10分) [编程]打印100以内的素数,在第三章二重循环的练习里实现过,现在用函数再次实现 -
二重循环打印的函数写法1.二重循环的时候,我们曾经打印过很多三角形,现在我们用函数再实现一次 (10分) [编程]生成连续n个字符写成一个函数genChar,它有两个参数,第一个是要打印的字符,第二个是打印的数量n,返回值是就是n个连续的字符
<code><div class='codeNewLine'><span class="comments">#这里是genChar函数定义</span></div><div class='codeNewLine'></div><div class='codeNewLine'></div><div class='codeNewLine'></div><div class='codeNewLine'></div><div class='codeNewLine'>c= genChar(<span class='string'>"*"</span>,5)</div><div class='codeNewLine'><span class='pyFunction'>print</span>(c)<span class="comments"># 将打印5个*</span></div></code>2.使用genChar打印矩阵(需要先完成2.1genChar函数的定义) (10分) [编程]下面的代码会打印10*10个字符'*'的矩阵,使用的是genChar
参考代码,打印一个5*6(5行6列)的符号为*的矩阵,genChar函数定义需要贴在上方<code><div class='codeNewLine'><span class="comments">#这是之前3.6二重循环打印10*10矩阵的代码</span></div><div class='codeNewLine'><span class='keyword'>for</span> i <span class='keyword'>in</span> <span class='pyFunction'>range</span>(1,10):</div><div class='codeNewLine'> line=<span class='string'>""</span></div><div class='codeNewLine'> <span class='keyword'>for</span> j <span class='keyword'>in</span> <span class='pyFunction'>range</span>(1,10):</div><div class='codeNewLine'> line=line+<span class='string'>"*"</span></div><div class='codeNewLine'> <span class='pyFunction'>print</span>(line)</div><div class='codeNewLine'></div><div class='codeNewLine'></div><div class='codeNewLine'></div><div class='codeNewLine'><span class="comments">#上一题genChar函数定义粘贴处,略</span></div><div class='codeNewLine'></div><div class='codeNewLine'></div><div class='codeNewLine'><span class="comments">#这是使用了函数genChar打印10*10矩阵的代码</span></div><div class='codeNewLine'><span class='keyword'>for</span> i <span class='keyword'>in</span> <span class='pyFunction'>range</span>(1,10):</div><div class='codeNewLine'> line=genChar(<span class='string'>'*'</span>,10)</div><div class='codeNewLine'> <span class='pyFunction'>print</span>(line)</div></code>3.(*)打印倒置三角形(需要先完成2.1genChar函数的定义) (10分) [编程]打印下面的三角形,*号之间用空格隔开
* * * * * * * * *
* * * * * * * *
* * * * * * *
* * * * * *
* * * * *
* * * *
* * *
* *
*4.打印三角形(需要先完成2.1genChar函数的定义) (10分) [编程]使用genChar,打印下面的三角形,一共九行,注意:每个*后面接着一个空格
*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
* * * * * * * *
* * * * * * * * *5.打印等腰三角形(需要先完成2.1genChar函数的定义) (8分) [编程填空]这段代码可以打印一个等腰三角形,按照注释要求补充代码<code><div class='codeNewLine'><span class="comments">#genChar定义处</span></div><div class='codeNewLine'></div><div class='codeNewLine'></div><div class='codeNewLine'></div><div class='codeNewLine'><span class='keyword'>for</span> i <span class='keyword'>in</span> <span class='pyFunction'>range</span>(1,10):</div><div class='codeNewLine'> <span class="comments"># 10-i个空格</span></div><div class='codeNewLine'> s=genChar( , )</div><div class='codeNewLine'> <span class="comments">#2*i-1个*</span></div><div class='codeNewLine'> s=s+genChar( , )</div><div class='codeNewLine'> <span class='pyFunction'>print</span>(s)</div></code>6.(**)打印到倒置的等腰三角形(需要先完成2.1genChar函数的定义) (10分) [编程]参照上一题,打印一个倒置的等腰三角形(也就是底在上)
第一行:0个空格17个*(2*8+1)
第二行:1个空格15个*(2*7+1)
第三行:2个空格13个*(2*6+1)
…………
第九行:8个空格1个*