本文最后更新于 2025-01-10T22:20:33+08:00
第五部分 函数 函数简介(function) - 函数也是一个对象
- 对象是内存中专门用来存储数据的一块区域
- 函数可以用来保存一些可执行的代码,并且可以在需要时,对这些语句进行多次的调用
- 创建函数:
def 函数名([形参1,形参2,...形参n]) :
代码块
- 函数名必须要符号标识符的规范
(可以包含字母、数字、下划线、但是不能以数字开头)
- 函数中保存的代码不会立即执行,需要调用函数代码才会执行
- 调用函数:
函数对象()
- 定义函数一般都是要实现某种功能的
定义函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 def fn () : print ('这是我的第一个函数!' ) print ('hello' ) print ('今天天气真不错!' ) def sum () : a = 123 b = 456 print (a + b)def fn2 (a , b ) : print (a,"+" ,b,"=" ,a + b) fn2(10 ,20 ) fn2(123 ,456 )
函数的参数 - 在定义函数时,可以在函数名后的()中定义数量不等的形参,
多个形参之间使用,隔开
- 形参(形式参数),定义形参就相当于在函数内部声明了变量,但是并不赋值
- 实参(实际参数)
- 如果函数定义时,指定了形参,那么在调用函数时也必须传递实参,
实参将会赋值给对应的形参,简单来说,有几个形参就得传几个实参
练习1:定义一个函数,可以用来求任意三个数的乘积 1 2 3 def mul (a,b,c ): print (a*b*c)
练习1:定义一个函数,可以根据不同的用户名显示不同的欢迎信息 1 2 3 4 5 6 def welcome (username ): print ('欢迎' ,username,'光临' )
参数传递实例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 def fn (a = 5 , b = 10 , c = 20 ): print ('a =' ,a) print ('b =' ,b) print ('c =' ,c)def fn2 (a ): print ('a =' ,a) b = 123 b = True b = 'hello' b = None b = [1 ,2 ,3 ] fn2(fn)def fn3 (a , b ): print (a+b)def fn4 (a ): a[0 ] = 30 print ('a =' ,a,id (a)) c = 10 c = [1 ,2 ,3 ] fn4(c)
不定长的参数: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 def sum (*nums ): result = 0 for n in nums : result += n print (result)def fn (*a ): print ("a =" ,a,type (a))def fn2 (*,a,b,c ): print ('a =' ,a) print ('b =' ,b) print ('c =' ,c)def fn3 (b,c,**a ) : print ('a =' ,a,type (a)) print ('b =' ,b) print ('c =' ,c)def fn4 (a,b,c ): print ('a =' ,a) print ('b =' ,b) print ('c =' ,c) t = (10 ,20 ,30 ) d = {'a' :100 ,'b' :200 ,'c' :300 } fn4(**d)
函数的返回值: 返回值,返回值就是函数执行以后返回的结果 可以通过 return 来指定函数的返回值 可以之间使用函数的返回值,也可以通过一个变量来接收函数的返回值
这是一个没有返回值的函数:
1 2 3 4 5 6 7 8 9 def sum (*nums ): result = 0 for n in nums : result += n print (result)
return 后边跟什么值,函数就会返回什么值 return 后边可以跟任意的对象(字符串,列表,字典),返回值甚至可以是一个函数
这是一个有返回值的函数:
1 2 3 4 5 6 7 8 9 def fn (): def fn2 () : print ('hello' ) return fn2 r = fn()
如果仅仅写一个return 或者 不写return,则相当于return None 在函数中,return后的代码都不会执行,return 一旦执行函数自动结束
return continue break三者的区别:
1 2 3 4 5 6 7 8 def fn4 () : for i in range (5 ): if i == 3 : return print (i) print ('循环执行完毕!' )
fn5 和 fn5()的区别
1 2 3 4 5 6 7 def fn5 (): return 10 print (fn5) print (fn5())
文档字符串(函数的描述) help 函数 help()是Python中的内置函数 通过help()函数可以查询python中的函数的用法 语法:help(函数对象)
1 2 3 4 5 6 7 8 9 10 11 12 13 help (print ) 结果: Help on built-in function print in module builtins:print (...) print (value, ..., sep=' ' , end='\n' , file=sys.stdout, flush=False ) Prints the values to a stream, or to sys.stdout by default. Optional keyword arguments: file: a file-like object (stream); defaults to the current sys.stdout. sep: string inserted between values, default a space. end: string appended after the last value, default a newline. flush: whether to forcibly flush the stream.
利用函数字符串编写函数说明 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def fn (a:int ,b:bool ,c:str ='hello' ) -> int : ''' 这是一个文档字符串的示例(尽量使用英文编写) 函数的作用:。。。。。 函数的参数: a,作用,类型,默认值。。。。 b,作用,类型,默认值。。。。 c,作用,类型,默认值。。。。 ''' return 10 help (fn)
函数的作用域和命名空间 作用域 作用域(scope) 作用域指的是变量生效的区域
1 2 3 4 5 6 7 8 9 10 b = 20 def fn (): a = 10 print ('函数内部:' ,'a =' ,a) print ('函数内部:' ,'b =' ,b) fn() print ('函数外部:' ,'a =' ,a)print ('函数外部:' ,'b =' ,b)
在Python中一共有两种作用域 全局作用域
函数作用域
变量的查找
当我们使用变量时,会优先在当前作用域中寻找该变量,如果有则使用,如果没有则继续去上一级作用域中寻找,如果有则使用, 如果依然没有则继续去上一级作用域中寻找,以此类推。直到找到全局作用域,依然没有找到,则会抛出异常: NameError: name ‘a’ is not defined
变量修改:
1 2 3 4 5 6 7 8 a = 20 def fn3 (): global a a = 10 print ('函数内部:' ,'a =' ,a)
命名空间 命名空间(namespace) 命名空间指的是变量存储的位置,每一个变量都需要存储到指定的命名空间当中 每一个作用域都会有一个它对应的命名空间 全局命名空间,用来保存全局变量。函数命名空间用来保存函数中的变量 命名空间实际上就是一个字典,是一个专门用来存储变量的字典
locals()用来获取当前作用域的命名空间 如果在全局作用域中调用locals()则获取全局命名空间,如果在函数作用域中调用locals()则获取函数命名空间 返回的是一个字典
1 2 3 4 5 6 7 scope = locals () print (type (scope)) scope['c' ] = 1000
1 2 3 4 5 6 7 8 9 10 11 12 def fn4 (): a = 10 global_scope = globals () global_scope['a' ] = 30 fn4()
递归 求10的阶乘
基础:
函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 def factorial (n ): ''' 该函数用来求任意数的阶乘 参数: n 要求阶乘的数字 ''' result = n for i in range (1 ,n): result *= i return result
递归式的函数: 从前有座山,山里有座庙,庙里有个老和尚讲故事,讲的什么故事呢? 从前有座山,山里有座庙,庙里有个老和尚讲故事,讲的什么故事呢?…. 递归简单理解就是自己去引用自己! 递归式函数,在函数中自己调用自己!
递归是解决问题的一种方式,它和循环很像
它的整体思想是,将一个大问题分解为一个个的小问题,直到问题无法分解时,再去解决问题 递归式函数的两个要件 1.基线条件
问题可以被分解为的最小问题,当满足基线条件时,递归就不在执行了
2.递归条件
递归和循环类似,基本是可以互相代替的,循环编写起来比较容易,阅读起来稍难,递归编写起来难,但是方便阅读
利用递归求阶乘:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 def factorial (n ): ''' 该函数用来求任意数的阶乘 参数: n 要求阶乘的数字 ''' if n == 1 : return 1 return n * factorial(n-1 )
递归练习 创建一个函数 power 来为任意数字做幂运算 n ** i 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 def power (n , i ): ''' power()用来为任意的数字做幂运算 参数: n 要做幂运算的数字 i 做幂运算的次数 ''' if i == 1 : return n return n * power(n , i-1 )
创建一个函数,用来检查一个任意的字符串是否是回文字符串 先检查第一个字符和最后一个字符是否一致,如果不一致则不是回文字符串 如果一致,则看剩余的部分是否是回文字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 def hui_wen (s ): ''' 该函数用来检查指定的字符串是否回文字符串,如果是返回True,否则返回False 参数: s:就是要检查的字符串 ''' if len (s) < 2 : return True elif s[0 ] != s[-1 ]: return False return hui_wen(s[1 :-1 ])print (hui_wen('abcdefgfedcba' ))
高阶函数 函数式编程 在Python中,函数是一等对象
一等对象一般都会具有如下特点: ① 对象是在运行时创建的 ② 能赋值给变量或作为数据结构中的元素 ③ 能作为参数传递 ④ 能作为返回值返回
高阶函数
高阶函数至少要符合以下两个特点中的一个 ① 接收一个或多个函数作为参数 ② 将函数作为返回值返回
一个普通的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 l = [1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ]def fn (lst ) : ''' fn()函数可以将指定列表中的所有偶数获取出来,并保存到一个新列表中返回 参数: lst:要进行筛选的列表 ''' new_list = [] for n in lst : if i % 2 == 0 :: new_list.append(n) return new_list
函数化编程:
检查一个任意的数字是否是偶数
1 2 3 4 5 6 def fn2 (i ) : if i % 2 == 0 : return True return False
这个函数用来检查指定的数字是否大于5
1 2 3 4 5 def fn3 (i ): if i > 5 : return True return False
主函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 def fn (func , lst ) : ''' fn()函数可以将指定列表中的所有偶数获取出来,并保存到一个新列表中返回 参数: lst:要进行筛选的列表 ''' new_list = [] for n in lst : if func(n) : new_list.append(n) return new_list
调用时,主函数可以直接选择调用任意函数,和参数 (规则和参数都作为输入) 当我们使用一个函数作为参数时,实际上是将指定的代码传递进了目标函数
filter()过滤器 1 2 3 4 5 6 filter ()可以从序列中过滤出符合条件的元素,保存到一个新的序列中 参数: 1. 函数,根据该函数来过滤序列(可迭代的结构) 2. 需要过滤的序列(可迭代的结构) 返回值: 过滤后的新序列(可迭代的结构)
示例:
1 2 3 4 5 r=filter (fn4 ,l)print (list (r))
匿名函数: 1 2 3 4 匿名函数 lambda 函数表达式 (语法糖) lambda 函数表达式专门用来创建一些简单的函数,他是函数创建的又一种方式 语法:lambda 参数列表 : 返回值 匿名函数一般都是作为参数使用,其他地方一般不会使用
示例:
1 2 3 4 5 6 7 8 9 10 11 12 def fn5 (a , b ): return a + blambda a,b : a + b 调用:整体加括号,参数也放进括号里 (lambda a,b : a + b)(10 ,20 ) fn6 = lambda a,b : a + b
对本节第一个程序的改造:
1 2 3 4 5 6 7 def fn4 (i ): return i % 3 == 0 r = filter (lambda i : i > 5 , l)print (list (r))
map()函数 1 2 3 4 5 6 7 l = [1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ] r = map (lambda i : i ** 2 , l)
sort()方法 1 2 3 4 5 6 7 8 9 10 11 12 l = ['bb' ,'aaaa' ,'c' ,'ddddddddd' ,'fff' ] l = [2 ,5 ,'1' ,3 ,'6' ,'4' ] l.sort(key=int )
sorted()函数 1 2 3 4 5 6 7 8 9 10 l = [2 ,5 ,'1' ,3 ,'6' ,'4' ]print ('排序前:' ,l)print (sorted (l,key=int )) print ('排序后:' ,l)
闭包 将函数作为返回值返回,也是一种高阶函数 这种高阶函数我们也称为叫做闭包,通过闭包可以创建一些只有当前函数能访问的变量 可以将一些私有的数据藏到的闭包中
语法示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 def fn (): a = 10 def inner (): print ('我是fn2' , a) return inner r = fn() r()
示例:求多个数的平均值:
正常写法:
1 2 3 4 nums = [50 ,30 ,20 ,10 ,77 ] print (sum (nums)/len (nums))
闭包:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 def make_averager (): nums = [] def averager (n ) : nums.append(n) return sum (nums)/len (nums) return averager averager = make_averager()print (averager(10 ))print (averager(20 ))print (averager(30 ))print (averager(40 ))
装饰器 现在有以下程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def add (a , b ): ''' 求任意两个数的和 ''' r = a + b return rdef mul (a , b ): ''' 求任意两个数的积 ''' r = a * b return r r = add(123 ,456 )print (r)
当前需求 :希望函数可以在计算前,打印开始计算,计算结束后打印计算完毕
我们可以直接通过修改函数中的代码来完成这个需求,但是会产生以下一些问题 ① 如果要修改的函数过多,修改起来会比较麻烦 ② 并且不方便后期的维护 ③ 并且这样做会违反开闭原则(OCP)
程序的设计,要求开发对程序的扩展,要关闭对程序的修改 我们希望在不修改原函数的情况下,来对函数进行扩展:
只需要根据现有的函数,来创建一个新的函数:
1 2 3 4 def fn2 (): print ('函数开始执行~~~' ) fn() print ('函数执行结束~~~' )
对add函数进行修改(记得传递参数)
1 2 3 4 5 6 7 8 def new_add (a,b ): print ('计算开始~~~' ) r = add(a,b) print ('计算结束~~~' ) return r
上边的方式,已经可以在不修改源代码的情况下对函数进行扩展了 但是,这种方式要求我们每扩展一个函数就要手动创建一个新的函数,实在是太麻烦了 为了解决这个问题,我们创建一个函数,让这个函数可以自动的帮助我们生产函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 def begin_end (old ): ''' 用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束 参数: old 要扩展的函数对象 ''' def new_function (*args , **kwargs ): print ('开始执行~~~~' ) result = old(*args , **kwargs) print ('执行结束~~~~' ) return result return new_function f = begin_end(fn) f2 = begin_end(add) f3 = begin_end(mul)
向begin_end()这种函数我们就称它为装饰器 通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展 在开发中,我们都是通过装饰器来扩展函数的功能的 在定义函数时,可以通过@装饰器,来使用指定的装饰器,来装饰当前的函数 可以同时为一个函数指定多个装饰器,这样函数将会安装从内向外的顺序被装饰
1 2 3 4 5 @begin_end def say_hello (): print ('大家好~~~' ) say_hello()
这个就相当于:
1 f = begin_end(say_hello)