5.6 函数的功能

下面的第3行代码是一次函数调用,称为调用func函数
a=6
b=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 -x
def f(x):
    y=x*x+5*abs(x)+6
    return y
def 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 y
def 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个*