Python基础语法之——函数
作者:Barranzi_
个人github主页:[github](https://github.com/La0bALanG)
个人邮箱:awc19930818@outlook.com
新时代的铁饭碗:一辈子不管走到哪里都有饭吃(还能吃上热乎的)。——佚名
免责声明:
本系列笔记撰写初衷就是为了分享个人知识以及个人学习历程中的感悟及思考,所涉及到的内容`仅供学习与交流`,请勿用作`非法或商业用途`!由此引发的任何法律纠纷`后果自负`,与作者本人无关!
版权声明:
未经作者本人授权,禁止转载!请尊重原创!
注:本文所有代码、案例测试环境:1.Linux -- 系统版本:Ubuntu20.04 LTS 2.windows -- 系统版本:WIN10 64位家庭版
函数基础概念
定义
通俗定义1:封装一段功能的代码段,再起一个名字
通俗定义2:函数是可以重复执行的语句块,可以重复使用
作用
-
提升代码的可重用性及可维护性
传统编码,即未采用函数封装或类封装的代码,在其结构层次上关系紊乱,且无法实现重用;尤其是当需要特定的复用某部分代码时,传统基础编码实现起来相对困难。在此基础上,为了解决代码重用,及某些基于函数思想的逻辑问题时,需要采用函数对代码进行封装,以达到复用的目的。
函数相关语法
-
函数的定义
def 函数名(参数列表): 函数体 -
函数的调用
函数名(传参列表) -
说明
- def:Python关键字,全称是define,中文意思为“定义”
- 函数名:本质上仍然是变量,意义则与变量一致,意为声明变量,绑定某以具体函数对象
- 参数:函数执行时所必须的数据。
- 函数体:完成该功能的所有代码。
- 注意:函数的第一行语句,建议使用文档字符串描述函数的功能、参数及其返回值类型。
-
return返回值:函数执行完毕后返回的结果
注意:
- return后无返回值,默认返回None
- 函数无return语句,默认返回None
- return的作用是返回结果,结果可以为任意类型数据(对象),所以return可返回一切类型的对象(包括返回一个函数对象 or 返回一个类)
建议:参考如下函数定义时的语法模板:
def 函数名([参数列表]):
'''
文档字符串:描述当前函数的功能,参数,及其返回值类型
:return:返回值类型
'''
语句块(函数体)
return 数据对象[None]
可变类型对象与不可变类型对象在传递参数时的区别
Python内置的可变类型:列表,字典,集合
Python内置的不可变类型:数字类型,字符串,元组,固定集合,字节串
Python的函数参数采取引用传递的方式。
- 如果Python函数的参数接收到的是可变类型的数据,比如列表或字典等,则可直接在函数内部修改参数对象的原始值;
- 如果Python函数的参数接收到的是不可变类型的数据,比如数字类型,字符串等,则不能直接在函数内部修改参数对象的原始值
函数的参数传递
-
实参的参数传递
-
位置传参:实参与形参的位置依次对应
注意:位置传参不可改变位置的先后顺序,尤其当多个类型的数据进行位置传参时,改变位置可能导致传入数据的类型不一致。
举个例子:
def fun(a,b,c): print(a,b,c) fun(1,2,3) -
序列传参:实参用*将序列拆解后与形参的位置依次对应
举个例子:
def fun(*l): print(l,type(l)) fun(10,20,30) -
关键字传参:实参根据形参的名字进行对应
举个例子:
def fun(name='张三'): print(name) fun(name='李四') -
字典关键字传参:实参用**将字典拆解后与形参的名字进行对应。
举个例子:
def fun(**kwargs): print(kwargs,type(kwargs)) fun(name='张三',age="19")作用:配合形参的缺省参数,可以让调用者进行随意传参
-
-
形参的参数传递
-
缺省参数
语法:
def 函数名(形参1=默认参数值,形参2=默认参数值,...): 函数体注意:
- 缺省参数必须自右至左依次存在,如果一个参数有缺省参数,则其右侧的所有参数都必须有缺省参数。
- 缺省参数可以有0个或多个,甚至全部都有缺省参数。
-
位置形参
语法:
def 函数名(形参1,形参2,...): 函数体 -
星号元组形参
语法:
def 函数名(*元组形参名): 函数体作用:收集多余的位置传参
说明:
- 一般命名为’args’
- 形参列表中最多只能有一个
-
命名关键字形参
语法:
def 函数名(*,命名关键字形参,...): 函数体作用:强制实参使用关键字传参
-
双星号字典形参
语法:
def 函数名(**字典形参名): 函数体作用:收集多余的关键字形参
说明:
- 一般命名为’kwargs’
- 形参列表中最多只能有一个
注意:实际应用中,一般将单星号元组形参,双星号字典形参一起使用,达到收集多余的关键字形参的目的
def 函数名(*args,**kwargs): 函数体 -
参数自左至右的顺序:位置形参 –> 星号元组形参 –> 命名关键字形参 –> 双星号字典形参
-
作用域LEGB
-
定义:变量起作用的范围
-
Python中作用域的划分
- 局部作用域local:函数内部
- 外部嵌套函数作用域enclosing:函数嵌套内区域
- 全局作用域global:模块(.py)内部
- 内置模块作用域builtin:builtin.py文件
-
变量的查找规则:按照作用域层级顺序由内向外:L – E – G – B
在访问变量时,先查找本地变量,然后是包裹此函数外部的函数内部的变量,之后是全局变量,最后是内置变量。
-
局部变量:定义在函数内部的变量
注意:形参也是局部变量。局部变量只能在函数内部使用,调用函数时才被创建,函数调用完毕后会销毁
-
全局变量:定义再函数外部,模块内部的变量。在整个模块(py文件)范围内访问(但函数内不能将其直接赋值)。
global与nonlocal语句
-
global语句
-
作用
- 在函数内部修改全局变量
- 在函数内部定义全局变量(全局声明)
-
语法
global 变量1,变量2,…
-
说明
- 在函数内直接为全局变量赋值,视为创建新的局部变量。
- 不能先声明局部的变量,再用global声明为全局变量。
-
-
nonlocal语句
- 作用:在内层函数修改外层嵌套函数内的变量
- 语法:nonlocal 变量1,变量2,…
- 说明:在被嵌套的内函数中进行使用
函数高级进阶
递归函数
-
定义:在函数内部通过一定方式调用自身的情况
-
递归函数的深度:函数内部调用自身的次数。次数越高,递归函数深度越大。
-
递归函数调用自身的方式
-
直接在函数内部执行调用语句
def fun(): ... fun()注意:此种方式容易陷入无限循环调用,即递归的深度无法控制
-
通过return返回值返回自身函数的调用
def fun(): ... return fun()注意:此种情况下一般需要添加终止递归深度逻辑,即一般配合if…else语句,让递归函数在某一情况下不在返回当前函数的调用,转为返回一个具体的数值,自动结束当前递归。
-
通过return返回值返回自身函数的引用
def fun(): ... return fun注意:这里返回的不再是函数的调用,而是函数的引用,因为没有加(),此种方式一般应用于实现闭包结构与装饰器
-
-
递归函数的理解与应用
- 递归函数,实质上就是被函数封装的一遍功能的循环。所以,while与for循环,在大部分时候可以转化为递归实现
- 使用递归函数时需注意,一定要控制递归的深度。当然如果不控制也没关系,Python各版本解释器对递归深度有最大限制,当递归深度达到一定量值时,递归函数将自动结束运行。
- 所谓递归的深度,其实与循环的可控意义是一样的。使用循环时需要避免程序进入死循环loop,递归也同样,即控制递归深度。
闭包结构与装饰器
-
闭包
-
定义:当函数执行完毕后,不释放局部变量的函数结构,称之为闭包结构。
-
理解:函数是一个对象。函数有声明就必须有调用。函数调用时创建局部变量,使用完毕后函数内的局部变量会被垃圾回收。如果在某些情况下,当函数调用完毕后,暂时还不想回收函数内的局部变量,则可以通过闭包结构实现。
-
闭包实现局部变量不被垃圾回收的原理:函数调用完毕后,返回一个新的函数对象引用,在这个新的函数对象中,引用着自身的局部变量,则只要新函数对象不调用,自身局部变量则一直存在。
-
闭包在Python中的应用:实现装饰器。
-
形成闭包结构的三要素
- 内外层函数嵌套
- 内层函数引用外层函数的局部变量
- 外层函数返回对内层函数的引用
-
举个例子
def out_(): a = 1 def in_(): print(a) return in_ out_()() 注意: 1.闭包结构先调用外层函数,获得对内层函数的引用,则此时的return返回值绑定到一个函数对象,该函数对象可重新绑定变量,即:fun = out_() 2.当需要调用内层函数时,直接调用该变量即可:fun(),因为此时变量fun绑定到了内层函数对象。 3.out_()()意为:先调用out_函数,拿到内层函数对象后跳过变量绑定直接继续调用内层函数对象。
-
-
装饰器decorators
-
定义:在不改变原函数的调用以及内部代码情况下,为其添加新功能的函数。
-
原理:装饰器的实现基于闭包结构
-
语法
def 装饰器函数名(函数对象): def 内层函数名([参数列表]): ... return 返回值 return 内层函数名 @装饰器函数名 def 原函数([参数列表]): ... return 返回值 原函数() -
说明:
-
除了Python内置的装饰器对象,自定义装饰器必须先定义才能使用
-
装饰器函数定义时需要将原函数作为参数进行传递
-
装饰器函数必须返回对内层函数的引用
-
@装饰器 语法必须添加在被装饰函数,也就是原函数上一行
-
@装饰器 语法原理:
原函数同名变量 = 装饰器函数(原函数参数)
-
-
注意:
-
装饰器本身可以为任意类型对象,并不是只能是函数
-
也就是说,一个装饰器,可能为函数,也可能为一个类或其他类型对象
-
装饰器链:一个对象可以被多个装饰器对象修饰,执行顺序为由近至远
def FUN1(fn): def in_(): print('aaa') return in_ def FUN2(fn): def in_(): print('bbb') return in_ @FUN1 @FUN2 def fun(): print('ccc') fun()#先执行装饰器FUN2,再执行装饰器FUN1,即:哪个装饰器距离被装饰函数越近,就先执行哪个。
-
-
Python内置高阶函数
-
高阶函数定义:函数作为参数进行传递的函数。即:高阶函数,传入的参数中存在具体的函数对象。
-
常见内置高阶函数介绍
-
map(函数对象,序列):将传入的函数依次作用于序列的每个元素,并且把结果作为新的序列返回。
举个例子:
#依次对序列的每个元素做立方运算 def fun(x): return x ** 3 print(list(map(fun,[i for i in range(10)])))注意:如果直接返回map函数调用后的返回值,其对象类型为map对象,并非可迭代对象。
-
filter(函数对象,序列):将传入的函数依次作用于序列的每个元素,并且把结果作为新的序列返回。作用与map类似,只不过添加过滤功能,其根据返回值是True还是False决定保留还是丢弃该元素
举个例子:
def fun(n): if n % 2 == 0: return True else: return False print(list(filter(fun,[x for x in range(1,20)]))) -
sorted(序列,key=函数对象,reverse=False):对所有可迭代对象进行排序操作
注意:reverse参数默认为False,代表默认升序排序,如需降序排序,则reverse=True
举个例子:
def fun(x): return x[0] l = [('age',18),('age',21),('age',25)] print(sorted(l,key=fun))
-
匿名函数:lambda表达式
-
定义:没有函数名的函数,定义时用变量赋值。
-
作用:
- 作为参数传递时语法简洁,优雅,代码可读性较强
- 随时创建和销毁,减弱代码的耦合度
-
语法:
-
定义
变量名 = lambda 形参:方法体 -
调用
变量名(参数)
-
-
说明:
- 形参如果没有可以不写
- 方法体只能有一条语句,且不支持赋值语句
- Python中的lambda表达式减弱了匿名函数的概念,局限性比较大
面向过程思想:函数式编程
- 定义:用一系列函数解决问题 – 典型面向过程思想
- 描述:
- 函数可以赋值给变量,赋值后变量即绑定函数
- 允许将函数作为参数传入另一个函数
- 允许函数返回一个函数
- 理解:
- 函数式编程大致意思可以理解为:一个函数调用时所需要的参数是另一个函数调用完毕后得到的返回值
- 函数式编程也可以通俗理解为使用函数进行代码的封装
- 函数式编程有其优劣势。优势:函数封装,代码结构清晰,功能整合简单;劣势:本质上属面向过程思想,在解决大型问题时不占优势。
- 采用函数式编程解决问题时需要注意的问题
- 高内聚低耦合:函数内的功能尽量单一,函数与函数之间尽量建立较少的联系。
- 理解:合理拆分当前功能模块,将每一类功能单独封装在一个函数中
- 函数需具备返回值,方便其他函数调用时使用


