函数简介
函数也是一个对象,对象是内存中专门存储数据的区域
函数可以保存一些可执行的代码,并且可以在需要时候可以对这些语句进行多次的调用
创建函数:
def 函数名(形参1,形参2): 代码块
调用函数:函数名()
fn是函数对象,fn()调用函数
print是函数对象,print()是调用函数
定义函数一般都是实现某种功能的,函数名必须要符合标识符的规范(可以包含数学、字母、下划线,但是不能以数字开头)
函数的参数
在定义函数时,可以在函数名后的括号里面定义数量不等的形参,多个形参之间可以使用逗号隔开
形参(形式参数),定义形参相当于在参数内部声明了变量,但是并不赋值
定义函数的时候指定形参,调用函数时来传递实参
定义形参时,可以给形参指定默认值,当没有实参时默认参数起作用
关键字参数可以不按照定义的顺序去传递,而是直接根据参数名去传递参数
混合使用位置参数和关键字参数时,必须将位置参数放到关键字参数前面
实参的类型
函数在调用的时候可以传递任意类型参数,解释器不会检查参数类型
如果形参执行的是一个对象,当我们通过形参修改对象时会影响所有该对象的变量
不定长参数
定义函数时,可以在形参前面加上一个*,这样这个形参就会获取所有的实参,它将会将所有的实参保存在一个元组中
可变参数不是必须写到左后,但是所有参数后的参数必须以关键字形式传递
可变参数后面的参数传递必须使用关键字传递实参
如果形参开头以*开头,后面的形参必须以关键字传递
*形参只能接受位置参数,而不能接受关键字参数
**形参可以接受其它的关键字参数,它会将这些参数统一保存在字典中,字典的key就是参数的名字,字典的value就是参数的值;这种形参只能有一个,必须写到最后
参数的解包
传递实参时也可以在序列类型参数前添加星号,这样也会自动的将序列中的元素依次进行赋值,要求序列的元素要与形参的个数一致
对字典解包的时候使用**参数
返回值
返回值就死函数执行后的返回的结果
可以通过return来指定函数的返回值,可以直接使用函数的返回值,也可以通过变量来接收函数的返回值,return后面跟什么值函数会返回什么值,后面可以跟任意对象,如果仅仅写一个return或者不写return,相当于return None
在函数中后面的代码都不会执行,return一旦执行函数自动结束
break退出当前循环,continue跳出当前循环
函数名字是函数的对象,函数名()是在调用函数对象
文档字符串(doc str)
help()函数可以查询一些Python中的函数用法,这里面传的是对象
在定义函数时,可以在函数内部编写文档字符串,文档字符串就是函数的说明,编写函数之后可以使用help(对象)来查看
可以利用下面方式指定类型
作用域(scope)
作用域指的是变量生效的区域
在Python中只有两种作用域:全局作用域、函数作用域
全局作用域在程序执行时创建,在程序执行结束时销毁
所有函数以外的区域都是全局作用域,在全局作用域定义的变量都属于全局变量,全局变量可以在程序的任意位置被访问
函数作用域在函数创建的时候创建,在调用结束时销毁
在函数作用域中定义的变量,都是局部变量,只能在函数内部被访问
变量的查找,会优先在当前的作用域中查找变量,如果有则使用,如果没有在上一级作用域中查找,以此类推,直到找到全局作用域依然没有找到,则会抛出异常
如果希望在函数内部需要修改全局变量,则需要用关键字global声明函数内部的使用a是全局变量,此时再去修改a时,就是在修改全局的a
命名空间(namespace)
命名空间指的是变量存储的位置,每一个作用域都需要存储在指定的命名空间当中
每一个作用域都有自己对应的命名空间
命名空间实际上就是专门用来存储变量的字典
locals()用来获取当前作用域的命名空间,如果在函数中调用locals()则获取函数命名空间
在函数内部调用locals()会返回函数的作用域
可用通过scope操作函数的命名空间,但是不建议
globals()函数可以在任意位置调用函数的命名空间
递归
尝试求10的阶乘(10!)
1! = 1
2! = 1 * 2
3! = 1 * 2 *3
...
求任意数的阶乘
递归简单理解就是自己引用自己
递归式函数就是在函数中自己调用函数
#结构: #无穷递归,如果函数被调用,除非程序的内存溢出,效果类似于死循环 def fn(): fn()
递归是解决问题的一种方式,它和循环很像,它整体思想是将一个大问题分解成一个小问题,直到问题无法分解时,再去解决问题
递归式函数两个要件:
-
基线条件:问题可以被分解成最小问题,当满足基线条件时,递归就不再执行了
-
递归条件:将问题分解的条件
10! = 10 * 9!
9! = 9 * 8!
...
2! = 2 * 1!
1! = 1
递归和循环类型,基本可以互相代替;循环编写起来比较容易,阅读起来稍难,递归编写起来稍难,阅读起来简单
练习
创建一个函数 power 来为任意数字幂运算 n ** i
10 ** 5 = 10 * 10**4
10 ** 4 = 10 * 10**3
...
10 ** 1 = 10
创建一个函数,来检查任意一个函数是否为回文,回文字符串从前往后和从后往前是一样的
abcdefgfedcba
先检查第一个字符是否和最后一个字符串是否一致,如果不一致则不是回文字符串
检查abcdefgfedcba是不是回文
检查bcdefgfedcb是不是回文
检查cdefgfedc是不是回文
检查defgfed是不是回文
...
检查fgf是不是回文
检查g是不是回文
高阶函数:
-
接受一个或多个函数作为参数
-
即将函数作为返回值返回(就是把函数中保存的代码,传到目标函数中)
filter()过滤器
filter可以从序列中过滤符合条件的元素,保存到一个新的序列
参数:函数、需要过滤的对象
返回值:过滤后的新序列
匿名函数lambda
语法: lambda 参数列表:返回值
map()函数:
map()函数可以对可迭代对象中中所有元素做指定的操作,然后将其添加到一个新的对象中返回
匿名函数一般都是作为参数使用,其他地方一般不会使用
sort()可以接受一个关键字参数,key,key需要一个函数作为参数,当设置了函数作为参数,每次都会以列表中的一个元素调用参数,并且使用函数的返回值来比较元素的大小
sort()该方法对列表中的元素进行排序
sorted(list,key)和sort()基本一致,但是sorted()可以对任意的序列进行排序,并且返回是一个新的对象,原序列不改变
闭包
形成闭包的条件:
-
函数嵌套
-
将内部函数作为返回值返回
-
内部函数必须使用外部的变量
装饰器
开闭原则(OCP)
程序的设计,要求开发对程序扩展,要关闭对程序的修改
在定义函数中可以使用@xxx,可以指定装饰器,可以为函数指定多个装饰器,这样函数将会按照由内向外的顺序被装饰