python-函数
函数 function
什么是函数:
函数是可以重复执行的语句块,可以重复使用
作用:
1、用于封装语句块,提高代码的重用性
2、定义用户级别的函数(自己可以创建函数)
函数定义(创建)语句 def 语句的语法:
def 函数名(形参列表):
语句块
说明:
1、函数的名字就是语句块的名字
2、函数名的命名规则与变量名相同(函数名必须为标识符(必须是字母或下划线开头,由字母数字下划线组成))
3、函数有自己的命名空间,在函数外部不可以访问函数内部的变量,在函数内部可以访问函数外部的变量,通常让函数处理外部数据需要用参数给函数传入一些 数据
4、函数的参数列表可以为空
5、语句部分不能为空。如果为空需要填充pass语句
函数的调用:返回调用函数后的引用关系
函数名(实际调用传递参数列表)
注:实际条用传递参数以后称为实参。单单一个函数名不加括号()返回的是函数的引用关系
说明:
函数调用是一个表达式
如果没有renurn语句,此函数执行完毕后返回None对象
如果函数需要返回其它的对象需要用到return语句
return 语句
语法:return [表达式] 。[]代表可以省略
作用:
用于函数中,结束当前函数的执行,返回到调用该函数的地方,同时返回一个对象的引用关系
说明:
1、return语句后跟的表达式可以省略,省略后相当于return None
2、如果函数没有return语句,则函数执行完最后一条语句后返回None(相当于在最后加了一条return None语句)
3、函数调用一定会返回一个对象的引用(默认返回None),函数调用一般会被执行两次,第一次是调用开始执行函数块,第二次得到返回对象的引用
python 函数的参数传递:
传递方式:
1、位置传参
实际参数(实参)的对应关系与形式参数(形参)的对应关系是按照位置来依次对应的
示例:def myfun(a,b,c):
pass
myfun(1,2,3)
说明:实参和形参通过位置进行传递的匹配,实参的个数必须与形参个数相同
2、序列传参(属于位置传参)
是指在函数调用过程中,用 * 将序列拆解后按位置传参的方式进行参数传递
示例:def myfun(a,b,c):
pass
s = [1,2,3]
myfun(*s) #表示把s拆开,等同于myfun(s[0],s[1],s[2])
s2 ="ABC"
nyfun(*s2) #表示把s2拆开
3、关键字传参
是指传参时,按照形参的名称给形参赋值,实参和形参按名称进行匹配
示例:def myfun(a,b,c):
pass
myfun(b=22,c=33,a=11) #等同于myfun(11,22,33)
说明:实参和形参可以不按照位置匹配
4、字典关键字传参(属于关键字传参)
是指实参为字典,将字典用** 拆解后进行关键字传参
示例:def myfun(a,b,c):
pass
d = {"c":33,"b":22,"a",11}
myfun(**d) #拆解字典后再传参
说明:字典的键名和形参名必须一致
字典的键名必须为字符串
字典的键名要在形参中存在
函数的综合传参:
函数传参方式,在能确定形参能唯一匹配到相应实参的情况下可以任意组合
示例:def myfun(a,b,c):
pass
myfun(100,*[200,300]) #正确
myfun(*"AB",300) #正确
myfun(100,c=300,b=200) #正确
myfun(1,**{"c":3,"b":2}) #正确
myfun(**{"c":3,"b":2},a=1) #正确
myfun(b=2,c=3,1) #错误,不能确定1给谁
myfun(a=1,b=2,3) #错误,传参需要先位置传参后关键字传参
说明:传参时,先位置传参,后关键字传参
******************************函数的形参(如何接收实参)**************************
函数的缺省参数
语法:def 函数名(形参名1=默认实参1,形参名2=默认实参2,......):
示例:def info(name,age=1,address=“未填写”):
print(name,“今年”,age,“岁,家庭地址“,address)
info(“xdl”,25)
info(“xdl”,25,“河南平顶山”)
info(“xdl”)
说明:1、缺省参数必须自右至左依次存在,如果一个参数有缺省值参数(且使用关键字传参,当使用位置传参时,右侧可以不是缺省参数),则其右侧的所有参数都 必须有缺省参数,如def test(a,b=10,c),是错误的
2、缺省参数可以有0个或多个,甚至全部都有缺省参数
3、缺省参数可以放在位置形参或命名关键字形参数
函数的形参定义方式:
1、位置形参
语法: def 函数名(形参名1,形参名2,.........):
2、*星号元组形参
语法:def 函数名(*元组形参名)
作用:收集多余位置的形参
说明:元组形参名通常用:args 表示(args代表元组)
示例:
3、命名关键字形参
语法:def 函数名(*,命名关键字形参):
语句块
或 def 函数名(*args,命名关键字形参):
语句块
作用:所有的参数都必须用关键字传参或字典关键字传参传递
示例:
4、**双星号字典形参
语法:def 函数名(**字典形参名):
语句块
作用:收集多余的关键字传参
说明:通常字典形参名定义为:kwargs
示例:
函数的参数说明:
缺省参数,位置形参,星号元组形参,命名关键字形参和双星号字典形参可以混合使用
函数参数自左至右的顺序为:(缺省参数可以放在位置形参或命名关键字形参)
位置形参
星号元组形参
命名关键字形参
双星号字典形参
综合示例:
函数的不定长参数:
语法:def fn(*args,**kwargs): #可以接收任意的位置传参和关键字传参
pass
全局变量和局部变量
局部变量:
定义在函数内部的变量称为局部变量(函数的形参也是局部变量)
局部变量只能在函数内部使用
局部变量在函数调用时才能够被创建,在函数调用之后会自动销毁
说明:
1、在函数内部首次对变量赋值是创建局部变量,再次为变量赋值是修改局部变量的绑定关系
2、在函数内部的赋值语句不会对全局变量造成影响
3、局部变量只能在其被声明的函数内部访问,而全局变量可以在整个模块范围内访问
全局变量
定义在函数外部,模块内部的变量称为全局变量
全局变量,所有的函数都可以直接访问(但函数内部不能将其直接赋值),函数名也是全局变量
globals 和 locals函数
globals() 返回当前全局作用域内变量的字典
locals() 返回当前局部作用域内变量的字典
示例:
函数变量:
函数名是变量,它在创建函数是绑定一个函数
示例:
一个函数可以作为另一个函数的参数传递
函数可以返回另一个函数(即:另一个函数可以返回一个函数)
函数的嵌套定义
是指一个函数里面用def语句来创建其他的函数
python 作用域
作用域也叫名字空间,是访问变量时,查找变量名的范围空间
python的四个作用域 LEGB
局部作用域 Local function L
外部嵌套函数作用域 Enclosing Function Locals E
函数定义所在模块(文件)的作用域 Global(Mudule) G
python内置模块的作用域 Builtin(python) B
变量名的查找规则:L-->E-->G-->B
在默认情况下,对变量名赋值会创建或改变本作用域内的变量
global语句
作用:
1、告诉解释器,global语句声明的一个或多个变量,这些变量的作用域为模块级的作用域,也称作全局变量
2、全局声明(global)将赋值变量映射到模块文内部的作用域
语法:global 变量1,变量2
示例: v =100
def fn():
global v
v = 200
fn()
print(v) #200
说明:
1、全局变量如果要在函数内部被赋值,则必须经过全局声明(否则会被认为是局部变量)
2、全局变量在函数内部不经过声明就可以直接访问
3、不能先声明局部的变量,再用global声明为全局变量,此做法不符合规则
4、global变量列表里的变量不能出现在此作用域内的形参列表里
nonlocal语句
作用:告诉解释器,nonlocal声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量
语法:nonlocal 变量名1,变量名2,......
示例:
说明:
1、nonlocal语句只能在被嵌套函数内部进行使用
2、访问nonlocal变量将对外部嵌套函数的作用域的变量进行操作
3、当有两层或两层以上的函数嵌套时,访问nonlocal变量值只对最近一层的变量进行操作
4、nonlocal语句的变量列表里的变量名,不能出现在此函数的形列表中
lambda 表达式(又称匿名函数)
作用:创建一个匿名函数对象,同def 类似,但不提供函数名
语法:lambda[参数1,参数2,......] :表达式 。[]里面的内容可以省略, 表达式只能有一个
示例:def myadd(x,y):
return x+y
上面函数等价于:myadd = lamnda x ,y :x+y
说明:
1、lambda只是一个表达式,它用来创建一个函数对象
2、当lambda表达式调用时,先执行冒号后(:)的表达式,并返回表达式的结果引用
3、lambda表达式创建的函数只能包含一条“表达式”
4、lambda比函数简单,且可以随时创建和销毁,有利于减少程序的耦合度
5、lambda的主体是一个表达式,而不是一个代码块,仅仅能在lambda表达式中封装有限的逻辑进去
d = [{"value": 16}, {"value": 17}] d.sort(key=lambda d: d["value"], reverse=True) print(d)
eval() 和exec()函数
eval()函数
格式:eval(source,global=None,locals=None)
作用:把一个字符串当成一个表达式来执行,返回表达式执行后的结果
示例:x = 100
y = 200
a = eval("x + y")
print(a) #300
exec()函数
作用:把一个字符串当成程序来执行
格式:exec(source,globals = None,locals=None)
示例:x = 100
y = 200
s = "z = x+y; print(z); del z;print("删除成功")"
exec(s)
eval 和 exec的两个参数globals 和 locals
此两个参数是用来设置“表达式”和“程序”运行的全局变量和局部变量
函数式编程
是指用一系列函数解决问题
函数是一等公民(一切最先的对待函数,程序是由函数基本单位组成的)
1、函数本身可以赋值给变量,赋值后变量绑定函数
2、允许将函数本身作为参数传入另一个函数
3、允许返回一个函数
函数的可重入性
是指一个函数传的参数一定,则结果必须一定
要求:def 定义的函数不要访问除局部变量以外的变量
高阶函数 High Order Fuction
什么是高阶函数:
满足下列一个条件的函数即为高阶函数
1、函数接受一个或多个函数作为参数传入
2、函数返回一个函数
python中内建(builtins)的高阶函数:
map ,filter,sorted
map函数:
map(func,*iterables) 用函数和对可迭代对象中的每一个元素作为参数计算出新的可迭代对象,当最短的一个可迭代对象不再提供数据时,此可迭代对象生成 结束
filter函数:
格式:filter(func,iterable)
作用:筛选可迭代对象iterable中的数据,返回一个可迭代对象,此可迭代对象将对iterable进行筛选
说明:函数func将对每个元素进行求值,返回False则将次数据丢弃,返回True则保留次数据
示例:
sorted 函数:
作用:将原可迭代对象的数据进行排序,生成排序后的列表
格式:sorted(iterable,key=None,reverse=False)
说明:1、iterable是可迭代对象
2、key函数是用来提供一个参考值,这个值将作为排序的依据
3、reverse表示用来设置是否倒序排列
递归函数 recursion
函数直接或间接的调用自身
递归说明:
递归一定要控制递归的层数,当符合某一条件时要终止递归
几乎所有的递归都能用while循环来代替,能用循环的优先考虑使用循环,
控制递归的层次的示例:
递归的优缺点:
优点:递归可以把问题简单化,让思路更为清晰,代码更简洁
缺点:递归因系统环境影响大,当递归深度太大时,可能会得到不可预知的结果
递归函数的实现方法:
先假设函数已经实现
练习
"""已知列表L=[[3,5,8],10,[[13,14],15,18],20],写一个函数print_list(lst)打印出所有元素,写一个函数sum_list(lst)返回这个列表中所有元素的和。""" L=[[3,5,8],10,[[13,14],15,18],20] def print_list(lst): for i in lst:#可能绑定列表,也可能绑定整数 if type(i) is list: print_list(i) else: print(i) print_list(L) def sum_list(lst): s=0 for i in lst:#在此处累加所有元素,包括列表 if type(i) is list: s += sum_list(i) else: s += i return s print(sum_list(L))
闭包 closure
将内嵌函数的语句和这些语句的执行环境打包在一起时,得到的对象称为闭包(closure)
闭包必须满足三个条件:
1、必须有一个内嵌函数
2、内嵌函数必须引用外部函数中的变量
3、外部函数返回值必须是内嵌函数
函数装饰器decorators(专业提高篇)
函数装饰器是指装饰的是一个函数,传入的是一个函数,返回的也是一个函数的函数
函数装饰器的语法:
def 装饰器函数名(参数):
语句块
return 函数对象
被装饰函数的语法:
@装饰器函数名
def 函数名(形参列表):
语句块
带有参数的装饰器及应用案例
#添加一个余额变动提醒消息功能 def message_send(fn): def fx(name,x): print("发送消息:",name,"来银行办理业务...") fn(name,x) print("发送消息:",name,"办理了",x,"元的业务...") return fx @message_send def savemoney(name,x): print(name,"存入",x,"元") @message_send def withdraw(name,x): print(name, "取出", x, "元") savemoney("小张" ,200) savemoney("小赵" ,500) withdraw("小王",300)
使用装饰器实现一个函数参数类型检查
from functools import wraps from inspect import getfullargspec def validate_input(obj, **kwargs): hints = obj.__annotations__ for param_name, param_type in hints.items(): if param_name == 'return': continue if not isinstance(kwargs[param_name], param_type): raise TypeError(f"参数:{param_name}类型错误,应该是:{param_type}") def add(a: int, b: float = 5.0) -> float: validate_input(add, a=a, b=b) return a + b def type_check(decorator): @wraps(decorator) # 执行wraps(decorator)返回一个partial def wrapped_decorator(*args, **kwargs): func_args = getfullargspec(decorator)[0] # ['a', 'b'] kwargs.update(dict(zip(func_args, args))) validate_input(decorator, **kwargs) return decorator(*args) # 或者 decorator(**kwargs) return wrapped_decorator @type_check def add2(a: int, b: float) -> float: return a + b if __name__ == "__main__": print(add(1)) print(add2(4, 6.0)) print(add2.__wrapped__(4, 6)) # 使用原来的函数
函数的文档字符串
函数内部,第一个没有赋值给任何变量的字符串为文档字符串,(如果函数内部第一个语句为赋值语句,则这个函数的文档字符串为空)
语法:def 函数名(形参列表):
''' 函数的文档字符串'''
语句块
可以使用help(函数名)来查看文档字符串
函数的__doc__属性
__doc__属性用于绑定该函数的文档字符串
示例:def fx(a,b):
"""这是函数的文档字符串
这是第二行"""
print(fx.__doc__)
函数的__name__属性:
__name__属性用于绑定函数名的字符串
示例 print(fx.__name__)#fx
函数定义语句(def语句的语法)
[@函数装饰器1]
[@函数装饰器2]
...
def 函数名([位置形参],[*[元组形参名]],[命名关键字形参],[**字典形参]):
"""文档字符串"""
语句块
注:[]里面的内容代表可省略
面试题: