函数简介(function)
- 函数也是一个对象 - 对象是内存中专门用来存储数据的一块区域 - 函数可以用来保存一些可执行的代码,并且可以在需要时,对这些语句进行多次的调用 - 创建函数: def 函数名([形参1,形参2,...形参n]) : 代码块 - 函数名必须要符号标识符的规范 (可以包含字母、数字、下划线、但是不能以数字开头) - 函数中保存的代码不会立即执行,需要调用函数代码才会执行 - 调用函数: 函数对象() - 定义函数一般都是要实现某种功能的
# 比如有如下三行代码,这三行代码是一个完整的功能 # print('Hello') # print('你好') # print('再见') # 定义一个函数 def fn() : print('这是我的第一个函数!') print('hello') print('今天天气真不错!') # 打印fn # print(fn) <function fn at 0x03D2B618> # print(type(fn)) <class 'function'> # fn是函数对象 fn()调用函数 # print是函数对象 print()调用函数 # fn() # 定义函数时指定形参 def fn2(a , b) : # print('a =',a) # print('b =',b) print(a,"+",b,"=",a + b) # 调用函数时,来传递实参 fn2(10,20) fn2(123,456)
函数的参数
- 在定义函数时,可以在函数名后的()中定义数量不等的形参, 多个形参之间使用,隔开 - 形参(形式参数),定义形参就相当于在函数内部声明了变量,但是并不赋值 - 实参(实际参数) - 如果函数定义时,指定了形参,那么在调用函数时也必须传递实参, 实参将会赋值给对应的形参,简单来说,有几个形参就得传几个实参
# 求任意三个数的乘积 def mul(a,b,c): print(a*b*c) # 根据不同的用户名显示不同的欢迎信息 def welcome(username): print('欢迎',username,'光临') # mul(1,2,3) # welcome('孙悟空') # 定义一个函数 # 定义形参时,可以为形参指定默认值 # 指定了默认值以后,如果用户传递了参数则默认值没有任何作用 # 如果用户没有传递,则默认值就会生效 def fn(a = 5 , b = 10 , c = 20): print('a =',a) print('b =',b) print('c =',c) # fn(1 , 2 , 3) # fn(1 , 2) # fn() # 实参的传递方式 # 位置参数 # 位置参数就是将对应位置的实参复制给对应位置的形参 # 第一个实参赋值给第一个形参,第二个实参赋值给第二个形参 。。。 # fn(1 , 2 , 3) # 关键字参数 # 关键字参数,可以不按照形参定义的顺序去传递,而直接根据参数名去传递参数 # fn(b=1 , c=2 , a=3) # print('hello' , end='') # 位置参数和关键字参数可以混合使用 # 混合使用关键字和位置参数时,必须将位置参数写到前面 # fn(1,c=30) def fn2(a): print('a =',a) # 函数在调用时,解析器不会检查实参的类型 # 实参可以传递任意类型的对象 b = 123 b = True b = 'hello' b = None b = [1,2,3] # fn2(b) fn2(fn) def fn3(a , b): print(a+b) # fn3(123,"456") def fn4(a): # 在函数中对形参进行重新赋值,不会影响其他的变量 # a = 20 # a是一个列表,尝试修改列表中的元素 # 如果形参执行的是一个对象,当我们通过形参去修改对象时 # 会影响到所有指向该对象的变量 a[0] = 30 print('a =',a,id(a)) c = 10 c = [1,2,3] # fn4(c) # fn4(c.copy()) # fn4(c[:]) # print('c =',c,id(c))
关注微信公众号,【python社区营】了解更多知识,及学习资源
不定长的参数
# 不定长的参数 # 定义一个函数,可以求任意个数字的和 def sum(*nums): # 定义一个变量,来保存结果 result = 0 # 遍历元组,并将元组中的数进行累加 for n in nums : result += n print(result) # sum(123,456,789,10,20,30,40) # 在定义函数时,可以在形参前边加上一个*,这样这个形参将会获取到所有的实参 # 它将会将所有的实参保存到一个元组中 # a,b,*c = (1,2,3,4,5,6) # *a会接受所有的位置实参,并且会将这些实参统一保存到一个元组中(装包) def fn(*a): print("a =",a,type(a)) # fn(1,2,3,4,5) # 带星号的形参只能有一个 # 带星号的参数,可以和其他参数配合使用 # 第一个参数给a,第二个参数给b,剩下的都保存到c的元组中 # def fn2(a,b,*c): # print('a =',a) # print('b =',b) # print('c =',c) # 可变参数不是必须写在最后,但是注意,带*的参数后的所有参数,必须以关键字参数的形式传递 # 第一个参数给a,剩下的位置参数给b的元组,c必须使用关键字参数 # def fn2(a,*b,c): # print('a =',a) # print('b =',b) # print('c =',c) # 所有的位置参数都给a,b和c必须使用关键字参数 # def fn2(*a,b,c): # print('a =',a) # print('b =',b) # print('c =',c) # 如果在形参的开头直接写一个*,则要求我们的所有的参数必须以关键字参数的形式传递 def fn2(*,a,b,c): print('a =',a) print('b =',b) print('c =',c) # fn2(a=3,b=4,c=5) # *形参只能接收位置参数,而不能接收关键字参数 # def fn3(*a) : # print('a =',a) # **形参可以接收其他的关键字参数,它会将这些参数统一保存到一个字典中 # 字典的key就是参数的名字,字典的value就是参数的值 # **形参只能有一个,并且必须写在所有参数的最后 def fn3(b,c,**a) : print('a =',a,type(a)) print('b =',b) print('c =',c) # fn3(b=1,d=2,c=3,e=10,f=20)
参数的解包(拆包)
# 参数的解包(拆包) def fn4(a,b,c): print('a =',a) print('b =',b) print('c =',c) # 创建一个元组 t = (10,20,30) # 传递实参时,也可以在序列类型的参数前添加星号,这样他会自动将序列中的元素依次作为参数传递 # 这里要求序列中元素的个数必须和形参的个数的一致 # fn4(*t) # 创建一个字典 d = {'a':100,'b':200,'c':300} # 通过 **来对一个字典进行解包操作 fn4(**d)
返回值
break 用来退出当前循环 continue 用来跳过当次循环 return 用来结束函数
# 返回值,返回值就是函数执行以后返回的结果 # 可以通过 return 来指定函数的返回值 # 可以之间使用函数的返回值,也可以通过一个变量来接收函数的返回值 def sum(*nums): # 定义一个变量,来保存结果 result = 0 # 遍历元组,并将元组中的数进行累加 for n in nums : result += n print(result) # sum(123,456,789) # return 后边跟什么值,函数就会返回什么值 # return 后边可以跟任意的对象,返回值甚至可以是一个函数 def fn(): # return 'Hello' # return [1,2,3] # return {'k':'v'} def fn2() : print('hello') return fn2 # 返回值也可以是一个函数 r = fn() # 这个函数的执行结果就是它的返回值 # r() # print(fn()) # print(r) # 如果仅仅写一个return 或者 不写return,则相当于return None def fn2() : a = 10 return # 在函数中,return后的代码都不会执行,return 一旦执行函数自动结束 def fn3(): print('hello') return print('abc') # r = fn3() # print(r) def fn4() : for i in range(5): if i == 3 : # break 用来退出当前循环 # continue 用来跳过当次循环 return # return 用来结束函数 print(i) print('循环执行完毕!') # fn4() def sum(*nums): # 定义一个变量,来保存结果 result = 0 # 遍历元组,并将元组中的数进行累加 for n in nums : result += n return result r = sum(123,456,789) # print(r + 778) def fn5(): return 10 # fn5 和 fn5()的区别 print(fn5) # fn5是函数对象,打印fn5实际是在打印函数对象 <function fn5 at 0x05771BB8> print(fn5()) # fn5()是在调用函数,打印fn5()实际上是在打印fn5()函数的返回值 10
help()
# help()是Python中的内置函数 # 通过help()函数可以查询python中的函数的用法 # 语法:help(函数对象) # help(print) # 获取print()函数的使用说明 # 文档字符串(doc str) # 在定义函数时,可以在函数内部编写文档字符串,文档字符串就是函数的说明 # 当我们编写了文档字符串时,就可以通过help()函数来查看函数的说明 # 文档字符串非常简单,其实直接在函数的第一行写一个字符串就是文档字符串 def fn(a:int,b:bool,c:str='hello') -> int: ''' 这是一个文档字符串的示例 函数的作用:。。。。。 函数的参数: a,作用,类型,默认值。。。。 b,作用,类型,默认值。。。。 c,作用,类型,默认值。。。。 ''' return 10 help(fn)
作用域(scope)
# 作用域(scope) # 作用域指的是变量生效的区域 b = 20 # 全局变量 def fn(): a = 10 # a定义在了函数内部,所以他的作用域就是函数内部,函数外部无法访问 print('函数内部:','a =',a) print('函数内部:','b =',b) # fn() # print('函数外部:','a =',a) # print('函数外部:','b =',b) # 在Python中一共有两种作用域 # 全局作用域 # - 全局作用域在程序执行时创建,在程序执行结束时销毁 # - 所有函数以外的区域都是全局作用域 # - 在全局作用域中定义的变量,都属于全局变量,全局变量可以在程序的任意位置被访问 # # 函数作用域 # - 函数作用域在函数调用时创建,在调用结束时销毁 # - 函数每调用一次就会产生一个新的函数作用域 # - 在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问 # # 变量的查找 # - 当我们使用变量时,会优先在当前作用域中寻找该变量,如果有则使用, # 如果没有则继续去上一级作用域中寻找,如果有则使用, # 如果依然没有则继续去上一级作用域中寻找,以此类推 # 直到找到全局作用域,依然没有找到,则会抛出异常 # NameError: name 'a' is not defined def fn2(): def fn3(): print('fn3中:','a =',a) fn3() # fn2() a = 20 def fn3(): # a = 10 # 在函数中为变量赋值时,默认都是为局部变量赋值 # 如果希望在函数内部修改全局变量,则需要使用global关键字,来声明变量 global a # 声明在函数内部的使用a是全局变量,此时再去修改a时,就是在修改全局的a a = 10 # 修改全局变量 print('函数内部:','a =',a) # fn3() # print('函数外部:','a =',a)
命名空间(namespace)
locals()用来获取当前作用域的命名空间
# 命名空间(namespace) # 命名空间指的是变量存储的位置,每一个变量都需要存储到指定的命名空间当中 # 每一个作用域都会有一个它对应的命名空间 # 全局命名空间,用来保存全局变量。函数命名空间用来保存函数中的变量 # 命名空间实际上就是一个字典,是一个专门用来存储变量的字典 # locals()用来获取当前作用域的命名空间 # 如果在全局作用域中调用locals()则获取全局命名空间,如果在函数作用域中调用locals()则获取函数命名空间 # 返回的是一个字典 scope = locals() # 当前命名空间 print(type(scope)) # print(a) # print(scope['a']) # 向scope中添加一个key-value scope['c'] = 1000 # 向字典中添加key-value就相当于在全局中创建了一个变量(一般不建议这么做) # print(c) def fn4(): a = 10 # scope = locals() # 在函数内部调用locals()会获取到函数的命名空间 # scope['b'] = 20 # 可以通过scope来操作函数的命名空间,但是也是不建议这么做 # globals() 函数可以用来在任意位置获取全局命名空间 global_scope = globals() # print(global_scope['a']) global_scope['a'] = 30 # print(scope) fn4()
递归
# 尝试求10的阶乘(10!) # 1! = 1 # 2! = 1*2 = 2 # 3! = 1*2*3 = 6 # 4! = 1*2*3*4 = 24 # print(1*2*3*4*5*6*7*8*9*10) # 创建一个变量保存结果 # n = 10 # for i in range(1,10): # n *= i # print(n) # 创建一个函数,可以用来求任意数的阶乘 def factorial(n): ''' 该函数用来求任意数的阶乘 参数: n 要求阶乘的数字 ''' # 创建一个变量,来保存结果 result = n for i in range(1,n): result *= i return result # 求10的阶乘 # print(factorial(20)) # 递归式的函数 # 从前有座山,山里有座庙,庙里有个老和尚讲故事,讲的什么故事呢? # 从前有座山,山里有座庙,庙里有个老和尚讲故事,讲的什么故事呢?.... # 递归简单理解就是自己去引用自己! # 递归式函数,在函数中自己调用自己! # 无穷递归,如果这个函数被调用,程序的内存会溢出,效果类似于死循环 # def fn(): # fn() # fn() # 递归是解决问题的一种方式,它和循环很像 # 它的整体思想是,将一个大问题分解为一个个的小问题,直到问题无法分解时,再去解决问题 # 递归式函数的两个要件 # 1.基线条件 # - 问题可以被分解为的最小问题,当满足基线条件时,递归就不在执行了 # 2.递归条件 # - 将问题继续分解的条件 # 递归和循环类似,基本是可以互相代替的, # 循环编写起来比较容易,阅读起来稍难 # 递归编写起来难,但是方便阅读 # 10! = 10 * 9! # 9! = 9 * 8! # 8! = 8 * 7! # ... # 1! = 1 def factorial(n): ''' 该函数用来求任意数的阶乘 参数: n 要求阶乘的数字 ''' # 基线条件 判断n是否为1,如果为1则此时不能再继续递归 if n == 1 : # 1的阶乘就是1,直接返回1 return 1 # 递归条件 return n * factorial(n-1) # print(factorial(10)) # 练习 # 创建一个函数 power 来为任意数字做幂运算 n ** i # 10 ** 5 = 10 * 10 ** 4 # 10 ** 4 = 10 * 10 ** 3 # ... # 10 ** 1 = 10 def power(n , i): ''' power()用来为任意的数字做幂运算 参数: n 要做幂运算的数字 i 做幂运算的次数 ''' # 基线条件 if i == 1: # 求1次幂 return n # 递归条件 return n * power(n , i-1) # print(power(8,6)) # # 练习 # 创建一个函数,用来检查一个任意的字符串是否是回文字符串,如果是返回True,否则返回False # 回文字符串,字符串从前往后念和从后往前念是一样的 # abcba # abcdefgfedcba # 先检查第一个字符和最后一个字符是否一致,如果不一致则不是回文字符串 # 如果一致,则看剩余的部分是否是回文字符串 # 检查 abcdefgfedcba 是不是回文 # 检查 bcdefgfedcb 是不是回文 # 检查 cdefgfedc 是不是回文 # 检查 defgfed 是不是回文 # 检查 efgfe 是不是回文 # 检查 fgf 是不是回文 # 检查 g 是不是回文 def hui_wen(s): ''' 该函数用来检查指定的字符串是否回文字符串,如果是返回True,否则返回False 参数: s:就是要检查的字符串 ''' # 基线条件 if len(s) < 2 : # 字符串的长度小于2,则字符串一定是回文 return True elif s[0] != s[-1]: # 第一个字符和最后一个字符不相等,不是回文字符串 return False # 递归条件 return hui_wen(s[1:-1]) #切片 # def hui_wen(s): # ''' # 该函数用来检查指定的字符串是否回文字符串,如果是返回True,否则返回False # 参数: # s:就是要检查的字符串 # ''' # # 基线条件 # if len(s) < 2 : # # 字符串的长度小于2,则字符串一定是回文 # return True # # 递归条件 # return s[0] == s[-1] and hui_wen(s[1:-1]) print(hui_wen('abcdefgfedcba'))
函数式编程
- 在Python中,函数是一等对象 - 一等对象一般都会具有如下特点: ① 对象是在运行时创建的 ② 能赋值给变量或作为数据结构中的元素 ③ 能作为参数传递 ④ 能作为返回值返回 - 高阶函数 - 高阶函数至少要符合以下两个特点中的一个 ① 接收一个或多个函数作为参数 ② 将函数作为返回值返回
高阶函数
# 高阶函数 # 接收函数作为参数,或者将函数作为返回值的函数是高阶函数 # 当我们使用一个函数作为参数时,实际上是将指定的代码传递进了目标函数 # 创建一个列表 l = [1,2,3,4,5,6,7,8,9,10] # 定义一个函数 # 可以将指定列表中的所有的偶数,保存到一个新的列表中返回 # 定义一个函数,用来检查一个任意的数字是否是偶数 def fn2(i) : if i % 2 == 0 : return True return False # 这个函数用来检查指定的数字是否大于5 def fn3(i): if i > 5 : return True return False def fn(func , lst) : ''' fn()函数可以将指定列表中的所有偶数获取出来,并保存到一个新列表中返回 参数: lst:要进行筛选的列表 ''' # 创建一个新列表 new_list = [] # 对列表进行筛选 for n in lst : # 判断n的奇偶 if func(n) : new_list.append(n) # if n > 5 : # new_list.append(n) # 返回新列表 return new_list # def fn4(i): # if i % 3 == 0: # return True # return False def fn4(i): return i % 3 == 0 # print(fn(fn4 , l))
filter()过滤器
# filter() # filter()可以从序列中过滤出符合条件的元素,保存到一个新的序列中 # 参数: # 1.函数,根据该函数来过滤序列(可迭代的结构) # 2.需要过滤的序列(可迭代的结构) # 返回值: # 过滤后的新序列(可迭代的结构) # fn4是作为参数传递进filter()函数中 # 而fn4实际上只有一个作用,就是作为filter()的参数 # filter()调用完毕以后,fn4就已经没用
匿名函数 lambda 函数表达式 (语法糖)
# 匿名函数 lambda 函数表达式 (语法糖) # lambda函数表达式专门用来创建一些简单的函数,他是函数创建的又一种方式 # 语法:lambda 参数列表 : 返回值 # 匿名函数一般都是作为参数使用,其他地方一般不会使用 def fn5(a , b): return a + b # (lambda a,b : a + b)(10,20) # 也可以将匿名函数赋值给一个变量,一般不会这么做 fn6 = lambda a,b : a + b # print(fn6(10,30)) r = filter(lambda i : i > 5 , l) # print(list(r))
map()
# map() # map()函数可以对可跌倒对象中的所有元素做指定的操作,然后将其添加到一个新的对象中返回 l = [1,2,3,4,5,6,7,8,9,10] r = map(lambda i : i ** 2 , l) # print(list(r))
sort()
# sort() # 该方法用来对列表中的元素进行排序 # sort()方法默认是直接比较列表中的元素的大小 # 在sort()可以接收一个关键字参数 , key # key需要一个函数作为参数,当设置了函数作为参数 # 每次都会以列表中的一个元素作为参数来调用函数,并且使用函数的返回值来比较元素的大小 l = ['bb','aaaa','c','ddddddddd','fff'] # l.sort(key=len) l = [2,5,'1',3,'6','4'] l.sort(key=int) # print(l)
sorted()
# sorted() # 这个函数和sort()的用法基本一致,但是sorted()可以对任意的序列进行排序 # 并且使用sorted()排序不会影响原来的对象,而是返回一个新对象 l = [2,5,'1',3,'6','4'] # l = "123765816742634781" print('排序前:',l) print(sorted(l,key=int)) print('排序后:',l)
闭包
# 将函数作为返回值返回,也是一种高阶函数 # 这种高阶函数我们也称为叫做闭包,通过闭包可以创建一些只有当前函数能访问的变量 # 可以将一些私有的数据藏到的闭包中 def fn(): a = 10 # 函数内部再定义一个函数 def inner(): print('我是fn2' , a) # 将内部函数 inner作为返回值返回 return inner # r是一个函数,是调用fn()后返回的函数 # 这个函数实在fn()内部定义,并不是全局函数 # 所以这个函数总是能访问到fn()函数内的变量 r = fn() # r() # 求多个数的平均值 # nums = [50,30,20,10,77] # sum()用来求一个列表中所有元素的和 # print(sum(nums)/len(nums)) # 形成闭包的要件 # ① 函数嵌套 # ② 将内部函数作为返回值返回 # ③ 内部函数必须要使用到外部函数的变量 def make_averager(): # 创建一个列表,用来保存数值 nums = [] # 创建一个函数,用来计算平均值 def averager(n) : # 将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))
装饰器
通过装饰器来扩展函数的功能的
*args所有未知参数 , **kwargs所有关键字参数
# 创建几个函数 def add(a , b): ''' 求任意两个数的和 ''' r = a + b return r def mul(a , b): ''' 求任意两个数的积 ''' r = a * b return r # 希望函数可以在计算前,打印开始计算,计算结束后打印计算完毕 # 我们可以直接通过修改函数中的代码来完成这个需求,但是会产生以下一些问题 # ① 如果要修改的函数过多,修改起来会比较麻烦 # ② 并且不方便后期的维护 # ③ 并且这样做会违反开闭原则(OCP) # 程序的设计,要求开发对程序的扩展,要关闭对程序的修改 # r = add(123,456) # print(r) # 我们希望在不修改原函数的情况下,来对函数进行扩展 def fn(): print('我是fn函数....') # 只需要根据现有的函数,来创建一个新的函数 def fn2(): print('函数开始执行~~~') fn() print('函数执行结束~~~') # fn2() def new_add(a,b): print('计算开始~~~') r = add(a,b) print('计算结束~~~') return r # r = new_add(111,222) # print(r) # 上边的方式,已经可以在不修改源代码的情况下对函数进行扩展了 # 但是,这种方式要求我们每扩展一个函数就要手动创建一个新的函数,实在是太麻烦了 # 为了解决这个问题,我们创建一个函数,让这个函数可以自动的帮助我们生产函数 def begin_end(old): ''' 用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束 参数:m old 要扩展的函数对象 ''' # 创建一个新函数 def new_function(*args , **kwargs): #*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) # r = f() # r = f2(123,456) # r = f3(123,456) # print(r) # 向begin_end()这种函数我们就称它为装饰器 # 通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展 # 在开发中,我们都是通过装饰器来扩展函数的功能的 # 在定义函数时,可以通过@装饰器,来使用指定的装饰器,来装饰当前的函数 # 可以同时为一个函数指定多个装饰器,这样函数将会安装从内向外的顺序被装饰 def fn3(old): ''' 用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束 参数: old 要扩展的函数对象 ''' # 创建一个新函数 def new_function(*args , **kwargs): print('fn3装饰~开始执行~~~~') # 调用被扩展的函数 result = old(*args , **kwargs) print('fn3装饰~执行结束~~~~') # 返回函数的执行结果 return result # 返回新函数 return new_function @fn3 @begin_end def say_hello(): print('大家好~~~') say_hello()
关注微信公众号,【python社区营】了解更多知识,及学习资源