zoukankan      html  css  js  c++  java
  • 第5.5节 函数递归、嵌套及样例

    一、    函数递归及嵌套简介
    1.    函数支持递归,递归就是函数可以在函数内调用自己,这种情况在C语言等语言就已经支持,不单独介绍;
    2.    Python支持函数内再定义函数,这种方式称为函数嵌套。函数内的函数称为局部函数,其上层函数称为封闭函数:
    1)    在默认情况下,局部函数对外部是隐藏的,局部函数只能在其封闭函数内有效;
    2)    封闭函数也可以返回局部函数,以便程序在其他作用域中使用局部函数,此时返回的函数在调用方使用时就可以等同于普通函数一样使用;
    3)    在局部函数中如果需要访问封闭函数的变量,需要使用nonlocal进行声明;
    4)    局部函数大多数情况下可以与封闭函数使用两个函数实现,但局部函数在某些特定场景下使用可以简化程序的实现方式。相关内容在后面章节再介绍。
      
    二、    函数其他的知识
    1.    要判断某个对象是否为函数可调用,可使用内置函数callable,该函数参数为需要判断的对象如函数名,返回值为布尔值,为True就表示可调用;
    2.    所有函数都是 function 对象,这意味着可以把函数本身赋值给变量,就像把整数、浮点数、列表、元组赋值给变量一样。举例:

    >>> def f(n1,n2,*n):
        print('n1=',n1,',n2=',n2,',numbers=',n)
    >>> add=f
    >>>type(add)  #结果为:<class 'function'>


    3.    可将函数作为其他函数的形参,通过使用函数作为参数可以在调用函数时动态传入函数,实际上就可动态改变被调用函数的部分代码;
    4.    Python 还支持使用函数作为其他函数的返回值;
    5.    如果函数需要有多个返回值,则既可将多个值包装成容器的元素如列表之后返回,也可直接返回多个值。如果 函数直接返回多个值,Python 会自动将多个返回值封装成元组。六、    案例
    1.    实现完整的可变参数的计算函数
    该函数输入一串至少2个数字的不限数量的数字,然后调用对应的运算符进行连续运算(如连加、连减、连乘等),如:cal(‘+’,1,2,3) 、cal(‘*’,1,2,3,4)结果为24。不多说,直接上代码:

    >>> def cal2var(number1,number2,calmethod): #实现2个数的运算,第三个参数为运算符
        if calmethod=='+':return  number1+number2;
        elif  calmethod=='-':return  number1-number2;
        elif  calmethod=='*':return  number1*number2;
        elif  calmethod=='/':return  number1/number2;
        else: raise ValueError('运算符必须是+-*/中的一个')
    >>> def cal(number1,number2,*numbers,calmethod='+'):
     #实现n个数的运算,第1个和第2个参数必须有且是整数,后面还可以跟随不限量的多个整数,最后一个参数为运算符
       print('number1=',number1,',number2=',number2,',numbers=',numbers,', calmethod=',calmethod) 
       calmethod=calmethod.strip() #去掉运算符前后的空格
       if len(calmethod)!=1: raise ValueError('运算符长度必须为1个字符') 
       if '+-*/'.find(calmethod)==-1 :raise ValueError('运算符必须是+-*/中的一个') 
       if not isinstance(number1,int): raise TypeError('第1个参数必须为整数') 
       if not isinstance(number2,int): raise TypeError('第2个参数必须为整数') 
       result=cal2var(number1,number2,calmethod)
       for i,n in enumerate(numbers): #注意使用了enumerate函数,请参见前面的章节《几个与迭代相关的函数》内容
           if  isinstance(n,int): #判断n是否为整数
               result=cal2var(result,n,calmethod)
           else:raise TypeError('第'+str(i+3)+'个参数必须为整数') 
       return result
    
    >>> cal(1,2,3,4,5,6)
    number1= 1 ,number2= 2 ,numbers= (3, 4, 5, 6) , calmethod= +
    21
    >>> cal(1,2,3,4,5,6,'*') #调用方式对吗?看结果
    number1= 1 ,number2= 2 ,numbers= (3, 4, 5, 6, '*') , calmethod= +
    Traceback (most recent call last):
      File "<pyshell#5>", line 1, in <module>
        cal(1,2,3,4,5,6,'*') #调用方式对吗?看结果
      File "<pyshell#3>", line 12, in cal
        else:raise TypeError('第'+str(i+3)+'个参数必须为整数')
    TypeError: 第7个参数必须为整数
    >>> cal(1,2,3,4,5,6,calmethod='*')
    number1= 1 ,number2= 2 ,numbers= (3, 4, 5, 6) , calmethod= *
    720
    >>> cal(1,2,3,4,5,6,7)
    number1= 1 ,number2= 2 ,numbers= (3, 4, 5, 6, 7) , calmethod= +
    28


        说明:
    1)    上述实现先定义了函数cal2var,实现两个数的运算,因为cal函数中需要先实现第一个和第二个参数的运算,后面才是可变个数的参数参与运算,为了简化代码,就定义了cal2var,该函数的定义可以直接放到函数cal函数中作为局部函数,使用效果是相同的;
    2)    看了cal函数的第一个print语句的输出就知道收集参数怎么使用;
    3)    cal函数的calmethod有缺省值,因此放在最后,如果不使用缺省值,就可以放在第一个,这样后面调用时就不用关键字参数方式调用,本例特地这样使用,实际上由于收集参数后面必须是关键字参数的形式,因此这个缺省值没有用,主要是为了演示收集参数的实参和形参匹配过程;
    4)    这个函数其实结合后面章节的动态执行方法有个更简单的实现方式,到时再演示。

    2.    使用递归函数和局部函数再次实现上述案例

    def cal(number1,number2,*numbers,calmethod='+'): 
    #实现n个数的运算,第1个和第2个参数必须有且是整数,
    #后面还可以跟随不限量的多个整数,最后一个参数为运算符
       def cal2var(number1,number2,calmethod): #局部函数实现2个数的运算,第三个参数为运算符
           if calmethod=='+':return  number1+number2;
           elif  calmethod=='-':return  number1-number2;
           elif  calmethod=='*':return  number1*number2;
           elif  calmethod=='/':return  number1/number2;
           else: raise ValueError('运算符必须是+-*/中的一个') 
       #由于递归调用传递参数时,将收集参数的数据(此时保存在元组内)作为参数传递,
       #导致实际numbers可能是包含一个元组元素的元组,因此需要将这种情况的元素去掉一层元组
       if len(numbers)==1:numbers=numbers[0]    
       print('number1=',number1,',number2=',number2,',numbers=',numbers,'(len=',len(numbers),'), calmethod=',calmethod) 
       calmethod=calmethod.strip() #去掉运算符前后的空格
       if len(calmethod)!=1: raise ValueError('运算符长度必须为1个字符') 
       if '+-*/'.find(calmethod)==-1 :raise ValueError('运算符必须是+-*/中的一个') 
       if not isinstance(number1,int): raise TypeError('第1个参数必须为整数') 
       if not isinstance(number2,int): raise TypeError('第2个参数必须为整数') 
       result = cal2var(number1,number2,calmethod) 
       if not len(numbers): return result
       ops=list(numbers)
       number=ops.pop(0)
       return cal(result,number,tuple(ops),calmethod='+')  
       return result


    执行截图:
     
    本节详细介绍了函数函数递归、函数嵌套以及函数的作用域相关内容,并进行了计算函数的实现。
    老猿Python(https://blog.csdn.net/LaoYuanPython)系列文章用于逐步介绍老猿学习Python后总结的学习经验,这些经验有助于没有接触过Python的程序员可以很容易地进入Python的世界。
    欢迎大家批评指正,谢谢大家关注!

  • 相关阅读:
    java 读取ini文件
    JPA简单的分页条件查询
    工厂模式之简单工厂模式,head first设计模式
    mvnw 找不到或无法加载主类,找不到符号,类
    spring boot 通过feign调用api接口
    Ubuntu18.04 samba配置
    log4cplus例子
    ES->PES->PS打包程序
    RED5安装与配置
    Java 常用的日志工具——JDK自带的java.util.logging包、APACHE 的log4j 与 slf4j日志处理接口
  • 原文地址:https://www.cnblogs.com/LaoYuanPython/p/11087719.html
Copyright © 2011-2022 走看看