• python函数参数、参数解构、作用域、递归及匿名函数


    一、python函数

    • 由若干语句组成的语句块,函数名称,参数列表构成,它是组织代码的最小单元,通过函数完成一定的功能

    1、函数的作用

    •  结构化编程对代码的最基本封装,一般按照功能组织一段代码
    •  封装的目的是为了功能复用,减少冗余代码
    •  使代码更加简洁美观,可读易懂

    2、函数的分类

    •  内建函数,如:max(),reversed()等
    •  库函数,如math.ceil()等

    3、函数的定义和调用

    定义

    • def语句定义函数
    •  函数名就是标识符,命名要求一样
    •  语句块必须缩进,约定4个空格
    •  python的函数若没有return语句,隐式会返回一个None值
    •  定义中的参数列表成为形式参数,只是一种符号表达,简称形参

    调用

    •  函数定义只是声明了一个函数,它不会被执行,需要调用
    •  调用方式,就是函数名加上小括号,括号内写参数
    •  调用时写的参数是实际参数,是实实在在的传入的值,简称实参

    二、函数参数

    •  参数调用时传入的参数要和定义的个数相匹配(可变参数例外)
    •  位置参数:按照参数定义顺序传入实参fn(1,2)
    •  关键字参数:使用形参的名字来传入实参的方式,如果使用了形参名字,那么传参顺序就可以随意fn(x=1,y=1)
    •  传参:要求位置参数必须在关键字参数之前传入,位置参数是位置对应的;

    1、函数参数默认值

    •   参数的默认值可以在未传入足够的实参的时候,对没有给定的参数赋值为默认值
    •   参数非常多的时候,并不需要用户每次都输入所有的参数,简化函数调用

    2、可变参数

    •  在形参前使用*表示该形参是可变参数,可以接收多个实参
    •  收集多个实参为一个tuple元组
        def add(*nums)
            >>> def add(*nums):
            sum = 0
            print(type(nums))
            for x in nums:
                sum += x
            print(sum)
            >>> add(3,6,9)
            <class 'tuple'>
            18

    3、可变关键字参数

    •  形参前使用**符号,表示可以接收多个关键字参数
    •  收集的实参名称和值组成一个字典
    >>> def show(**kwargs):
            for k,v in kwargs.items():
                print('{}={}'.format(k,v))
            >>> show(a=1,b=2,c=3)
            a=1
            c=3
            b=2

    4、参数总结

    •  有位置可变参数和关键字可变参数
    •  位置可变参数在形参前使用一个冒号*
    •  关键字可变参数在形参前使用两个冒号**
    •  位置可变参数和关键字可变参数都可以收集若干个实参
    •  混合使用参数的时候,可变参数要放到参数列表的最后,普通参数放在前面
        >>> def fn(x,y,*args,**kwargs):
                print(x)
                print(y)
                print(args)
                print(kwargs)
        
            >>> fn(3,5,6,9,10,a=1,b='python')
            3
            5
            (6, 9, 10)
            {'a': 1, 'b': 'python'}
            >>> fn(3,5)
            3
            5
            ()
            {}
            >>> fn(3,5,a=1,b='python')
            3
            5
            ()
            {'a': 1, 'b': 'python'}
            >>> 


    5、keyword-only参数

    •  如果在一个冒号参数后,或者一个位置可变参数后,出现的普通参数,实际上已经不是普通的参数了,
    •  而是keword-only参数
        >>> def fn(*args,x):
                print(x)
                print(args)
        >>> fn(3,5)  调用报错
        >>> fn(3,5,x=7)    
        args已经截获了所有的位置参数,x不使用关键字参数就不可能拿到实参
        
        >>> def fn(*kwargs,x):
                print(x)
                print(args)
        直接报语法错误,因为kwargs会截获所有的关键字参数


    6、参数规则

    • 参数列表一般顺序是,普通参数,缺省参数,可变位置参数,keword-only参数,可变关键字参数
    >>> def fn(x,y,z=3,*args,m=4,n,**kwargs):
                print(x,y,z,m,n)
                print(args)
                print(kwargs)
                
        def connect(host='localhost', port='3306', user='admin', password='admin', **kwargs):
        
        >>> def connect(host='localhost', port='3306', user='admin', password='admin', **kwargs):
            print(host,port)
            print(user,password)
            print(kwargs)
            >>> connect(db='cmdb')
            localhost 3306
            admin admin
            {'db': 'cmdb'}
            >>> connect(host='192.168.1.1',db='cmdb')
            192.168.1.1 3306
            admin admin
            {'db': 'cmdb'}
            >>> 

    三、参数解构

    •  给函数提供实参的时候,可以在集合类型前使用*或者**,把集合类型的结构解开,提取所有元素作为函数的实参
    •  非字典类型使用*解构成位置参数
    •  字典类型使用**解构成关键字参数
    •  提取出来的元素数目要和参数的要求匹配,也要和参数的类型匹配
    举例:
            >>> def add(x,y):
                return x+y
        
            1、位置参数解构
            >>> add(*(4,5))
            9
            >>> add(*[4,5])
            9
            >>> 
            
            2、关键字参数解构
            >>> d = {'x':5,'y':6}
            >>> add(**d)
            11
            >>> 
    
            3、参数解构和可变参数
            >>> def add(*args):
                    result = 0
                    for x in args:
                        result += x
                    return result
    
            >>> add(1,2,3)
            6
            >>> add(*[1,2,4])
            7
            >>> add(*range(10))
            45
            >>> 

    四、函数的返回值和作用域

    1、返回值

    • python函数使用return语句返回值,所有函数都有返回值,如果没有return,会隐式调用return None
    •  return语句并不一定是函数的语句最后一条语句
    •  一个函数可以存在多个return语句,但是只有一条可以被执行,如果没有一条return语句被执行到,就执行隐式retnurn
    •  如果有必要,可以显示调用return None,可以简写为return
    •  如果函数执行了return语句,函数就会返回,当前被执行的return语句之后的其他语句不会被执行
    •  return的作用是结束函数调用,返回值不能同时返回多个值

    2、作用域

    •  全局作用域:在整个程序运行环境中都可见
    •  局部作用域:在函数,类等内部可见,局部变量使用范围不能超过其所在的局部作用域
    举例:
        x = 5
        >>> def foo():
            x += 1
            print(x)
        >>> foo()
        x += 1其实是x = x+1,相当于在foo内部定义一个局部变量x,那么foo内部所有x都是这个局部变量
        但是这个x还没有完成赋值,就被右边拿来使用了,导致报错 
        
        使用全局变量global关键字变量,将foo内的x声明为使用外部的全局作用域中定义的x
        全局作用域中必须要有x的定义
        
        >>> def foo():
                global x
                x = 10
                x += 1 #x在内部作用域为一个外部作用域的变量赋值,所以x += 1不会报错
                print(x)
        >>> foo()

     
    3、全局作用域global

    •  外部作用域变量对内部作用域可见,但也不要在这个内部的局部作用域中直接使用;
    •  因为函数的目的就是为了封装,尽量与外界隔离
    •  如果函数需要使用外部全局变量,请使用函数的形参传参解决
    •  一句话:不用global

    五、递归函数

    •  函数直接或者间接调用自身就是递归
    •  递归一定要有边界条件,递归前进段,递归返回段
    •  当边界条件不满足的时候,递归前进段
    •  当边界条件不满足的时候,递归返回

    1、递归要求

    •  递归一定要有退出条件,递归调用一定要执行到这个退出条件,没有退出条件的递归就是无限调用
    •  递归调用的深度不宜过深,pthon对递归调用的深度做了限制,以保护解释器
    斐波那契数列Fibonacci number:1,1,2,3,5,8,13,21,34,55.....
    如果设F(n)为该数列的第n项,那么这句话可以写成如下形式:F(n)=F(n-1)+F(n-2)
    F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)
    
    pre = 0
    cur = 1
    print(pre,cur,end='')
    n = 4
    for i in range(n-1):
        pre,cur = cur,pre+cur
        print(cur,end='')
    
    解析:
    fib(3)+fib(2)
    fib(3)调用fib(3),fib(2),fib(1)

    2、递归的性能

    • 斐波那契数列求值性能改进
    递归举例:
    import datetime
    
    n = 35
    start = datetime.datetime.now()
    
    def fib(n):
        return 1 if n<2 else fib(n-1) + fib(n-2)
    
    for i in range(n):
        print(fib(i),end='')
    delta = (datetime.datetime.now() - start).total_seconds()
    print(delta)
    
    
    改下后:
    pre = 0
    cur = 1
    
    print(pre,cur.end='')
    def fib(n,pre=0,cur=1):
        pre,cur = cur, pre+cur
        print(cur,end='')
        if n == 2:
            return
        fib(n-1,pre,cur)
    fib(n)

    3、递归总结

    •  递归是一种很自然的表达,符合逻辑思维
    •  递归相对运行效率低,每一次调用函数都要开辟栈帧
    •  递归有深度限制,如果递归层次太深,函数反复压栈,栈内存很快就溢出
    •  递归可以用循环实现,即使递归代码简洁,能不用递归则不用

    六、匿名函数

    •  使用lambda关键字来定义匿名函数:lambda 参数列表:表达式:  如lambdax:x**2
    •  参数列表不需要小括号,冒号是用来分割参数列表和表达式的 
    •  不需要使用return,表达式的值就是匿名函数的返回值
    •  lambda表达式只能写在一行,被称为单行函数
    •  主要用途于高阶函数传参时,使用lambda表达式简化代码
    举例:
            >>> print((lambda :0)())
            0
            >>> print((lambda x,y=3:x+y)(5))
            8
            >>> print((lambda x,*,y=30:x+y)(5))
            35
            >>> print((lambda x,*,y=30:x+y)(5,y=10))
            15
            >>> print((lambda *args:(x for x in args))(*range(5)))
            <generator object <lambda>.<locals>.<genexpr> at 0x0000000003074258>
  • 相关阅读:
    关于Entity Framework中的Attached报错的完美解决方案
    关于C# Winform DataGridView 设置DefaultCellStyle无效的原因与解决方案
    实现winform DataGridView控件判断滚动条是否滚动到当前已加载的数据行底部
    关于Entity Framework自动关联查询与自动关联更新导航属性对应的实体注意事项说明
    阅读《LEARNING HARD C#学习笔记》知识点总结与摘要系列文章索引
    阅读《LEARNING HARD C#学习笔记》知识点总结与摘要五
    C# Winform 通过FlowLayoutPanel及自定义的编辑控件,实现快速构建C/S版的编辑表单页面
    NPOI导入导出EXCEL通用类,供参考,可直接使用在WinForm项目中
    阅读《LEARNING HARD C#学习笔记》知识点总结与摘要四
    C#实现通用数据过滤窗体
  • 原文地址:https://www.cnblogs.com/jiangzuofenghua/p/11386431.html
Copyright © 2020-2023  润新知