函数

函数

Python 函数

1.有若干语句组成的语句块、函数名称、参数列表构成,它是组织代码的最小单元
2.完成一定的功能

函数的作用

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

函数的分类

1. 内建函数,如max()、reversed()等
2.库函数,如math.ceil()等
3.自定义函数,使用def关键字定义

函数定义

 def 函数名(参数列表):
 函数体(代码块)
 [return 返回值]
 1.函数名就是标识符,命名要求一样
 2.语句块必须缩进,约定4个空格
 3.Python的函数若没有retuern语句,会隐式返回一个None值
 4.定义中的参数列表成为** 形式参数 **,只是一种符号表达(标识符),简称** 形参 **

函数调用

 1.函数定义,只是声明了一个函数,它不能被执行,,需要调用执行
 2.调用方式,就是** 函数名后加上小括号 **,如果有必要在括号内填上参数
 3.调用时写的参数是实际参数,是实实在在传入的值,简称实参
 def add(x,y):      函数定义
     result = x + y 函数体
     return result  返回值
 out = add(4,5)     函数体调用,可能有返回值,使便量接收这个返回值
 print(out)         print函数加上括号也是调用

 上面代码的解释:
    1.定义一个函数add,及函数名add,能接受2个参数
    2.该函数计算的结果通过返回值返回,需要return语句
    3.调用时,通过该函数名add后面加2个参数,返回值可以使用变量接收
    4.** 函数名也是标识符,返回值也是值 **
    5.定义需要在调用前,也就是说调用时,已经被调用过了,否则抛 NameError异常
    6.** 函数是可调用的对象**  callable()

函数参数

 1.函数在定义时要约定好形式参数,调用时也提供足够的实际参数,一般来说,形参和实参的个数要一致(可变参数除外)
传参方式
1.位置传参
 定义时 def f(x,y,z),调用时使用f(x=1,y=3,z=5),按照参数定义的顺来传入实参
2. 关键字传参
 定义时 def f(x,y,z),调用时使用f(x=1,y=3,z=5),实用形参的名字来传入实参的方式,如果使用了形参的名字,传参的顺序就可以和定义顺序不同
** 要求位置参数必须在关键字参数之前**传入,位置参数是按照位置对应的

   def f(x,y,z):
      pass

   f(z=None,y=10,x=[1])
   f((1,),z=6,y=4.1)
   f(y=5,z=6,2)  #错误传参
参数缺省值

缺省值也称为默认值,可以在函数定义时,为形参增加一个缺省值。其作用:
1.参数的默认值可以在未传入足够实参的时候,对没有给定的参数赋值为默认值
2.参数非常多的时候,并不需要用户每次都输入所有的参数,简化函数的调用

可变位置参数
 1.在形参前使用 * 表示该形参是可变位置参数,可以接受多个实参
 2.它将收集来的实参组织到一个tuple 中
可变关键字参数
 1.在形参前使用 ** 表示改形参是可变关键字参数,可以接受多个关键字参数
 2.它将收集来的实参的名称和值,组织到一个dict中
总结
 1.有可变位置参数和可变关键字参数
 2.可变位置参数在形参前使用一个星号*
 3.可变关键字参数在形参前使用两个星号 **
 4,可变位置参数和可变关键字参数都可收集若干个实参,可变位置参数收集形成一个tuple,可变关键字参数收集形成一个dict
 5.混合使用参数的时候,普通参数需要放到参数列表前面,可变参数要放到参数列表后面,可变位置参数需要放到可变关键字之前
keyword-only 参数
 keyword-only参数:在形参定义时,在一个*之后,或一个可变位置参数之后,出现的普通参数,就已经不时普通参数了,成为keyword--only参数
 ** 参数列表的参数一般顺序是:普通参数、缺省参数、可变位置参数、Keyword-only参数( 可带缺省值)、可变关键字参数**
注意
 1.定义最常用参数为普通参数,可不提供缺省值,必须由用户提供。注意这些参数的顺序,最常用的先定义
 2.将必须使用名称的才能使用的参数,定义为keyword-only参数,要求必须使用关键字传参
 3.如果函数有很多参数,无法逐一定义,可使用可变参数。如果需要定义这些参数的意义,则使可变关键字参数收集

参数结构

1.在给函数提供实参的时候,可以在迭代对象前使用 * 或者 **来进行函数的解构,提取出其中所有的元素作为函数的实参
2.使用 *解构成位置传参
3.使用 ** 解构成关键字传参
4.提取出来的元素数目要和参数的要求匹配

函数返回值

1.Python 语句使用return语句返回“返回值”
2.所有函数都有返回值,如果没有return语句,隐式调用return None
3.return语句并不一定是函数语句块的最后一条语句
4.一个函数可以存在多个return语句,但是只有一条可以被执行,如果没有一条return语句被执行到,隐式调用return None
5.如果有必要可以显示调用return None,可以简写return
6.如果函数执行了return语句,函数就会返回,当前被执行的return语句之后其他的语句就不会被执行了
7.返回值的作用:结束函数调用、返回“返回值”,只能返回一个返回值

函数作用域

作用域
一个标识符的可见范围,这就是标识符的作用域,一般来说的是变量的作用域
  
  def foo():
     x=100

print(x)
上例中x不能被访问到,会抛出异常(NameError:name'y'is not defined),原因在于函数就是一个人封装,它会开辟一个**作用域**,x变量被限制在这个作用域中,所以在函数外部x变量**不可见**
 
注意:每一个函数都会开辟一个作用域

作用域分类

全局作用域
1.在整个程序运行环境中都可见
2.全局作用域中的变量称为**全局变量**
局部作用域
1.在函数、类等内部可见
2.局部作用域中的变量称为**局部变量**,其使用范围不能超过其所在局部作用域
3.也称为**本地作用域**local

注意:
1.一般来讲外部作用域变量可以在函数内部可见,可以使用
2.反过来,函数内部的局部变量,不能再函数外部看到

函数嵌套

global 语句
    1. 外部作用域变量会在内部作用域可见,但也不要在这个内部的局部作用域中直接使用,因为函数的目的就是为了封装,尽量与外界隔离
    2.如果函数需要使用外部全局变量,尽量使用函数的形参定义,并在调用时传实参解决
    3.**不用global**

闭包

自由变量
    未在本地作用域中定义的变量,例如定义在内层函数外的外层函数作用域中的变量

####闭包
** 闭包就是一个概念,出现在嵌套函数中,指的是内层函数引用到了外层函数的局部变量,就形成了闭包 **

nonlocal
  nonlocal:将变量标记为不在本地作用域定义,而是在**上级的某一级局部作用域**中定义,但是**不能是全局作用域**中定义

变量名解析原则LEGB

 1.Local,本地作用域,局部作用域的local命名空间。函数调用时创建,调用结束消亡
 2.Enclosing,Python2.2时引入了嵌套函数,实现了闭包,这个就是嵌套函数的外部函数的命名空间
 3.Global,全局作用域,即一个模块的命名空间。模块被import时创建,解释器退出时消亡
 4.Bulid-in,内置模块的命名空间,生命周期从python解释器启动时创建解释器退出时消亡,例如 print(open),print和open都是内置变量

函数的销毁

 1.定义一个函数就是生成一个函数对象,函数名指向的就是函数对象
 2.可以使用 del 语句删除函数,使其引用计数减1
 3.可以使用同名标识符覆盖原有定义,本质上也是使其引用计数减1
 4.Python程序结束时,所有对象销毁
 5.函数也是对象,也不例外,是否销毁,还是得看引用计数是否为0

函数匿名

匿名:隐藏名字,既没有名称
匿名函数: 没有名字的函数
Lambda 表达式构建匿名函数
1.使用Lambda 表达式定义匿名函数,格式为Lambda[参数列表]:表达式
2.参数列表不需要小括号。无参就不写参数
3.冒号用来分割参数列表和表达式部分
4.不需要使用return。表达式的值,就是匿名函数的返回值,表达式中不能出现等号
5.lambda表达式(匿名函数)**只能写在一行上**,也称为单行函数。

递归函数 Recursion

递归要求
 1.递归一定要有退出条件,递归调用一定要执行这个退出条件,没有退出条件的递归调用,就是无限调用
 2.递归调用的深度不宜过深
   (1)python对递归调用的深度做了限制,以保护解释器
   (2)超多递归深度限制,抛出 RecursionError:maxinum recursion depth exceeded 超出最大深度
   (3)sys.getrecursionlimit()
**间接递归**
     间接递归是通过别的函数调用了韩式自身,但是,如果构成了递归循环是很危险的,但是往往这种情况在代码复杂的情况下,还是可能发生这种调用,要用代码的规范来避免这种递归调用的产生

递归总结

 1.递归是一种很自然的表达符合逻辑思维
 2.递归相对运行效率低,每一次调用函数都需要开辟栈帧
 3.递归要有深度限制,如果递归层次太深,函数反复压栈,栈内存很快就溢出了
 4.如果是有次数的递归,可以使用递归调用,或者使用循环代替,循环代码稍微复杂一些,但是只要不是死循环,可以多次迭代直至算出结果
 5.绝大数递归都可以使用循环实现
 6.即使递归代码很简洁,但是能不用则不用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值