函数
函数是盛放一系类代码功能的容器,先定义后调用
使用函数的好处
1.提高组织结构清晰,增强可读性
3.可重复使用,减少相同代码的重复
2.可扩展性提高
函数的两个阶段
定义阶段:申请内存空间将函数体放进去,将内存地址绑定给函数名
调用阶段: 通过函数名等到函数体的地址
定义阶段时只检测语法不执行代码,调用阶段才会执行函数体逻辑错误才会被检查到。
def 函数名(参数1,参数2): 函数名一般是动词 # 定义阶段 下面所有缩进的代码都是函数体
"""
为函数添加说明说明
"""
代码1...
代码2...
return 值
函数名(参数1,参数2) # 调用阶段
# 定义检测语言
def aa():
qwe # 没有定义qwe是什么,但语法上没有错误
# 运行程序 进程已结束,退出代码为 0
# 调用时翻译代码并执行
aa()
# NameError: name 'qwe' is not define
# 没有定义 qwe 逻辑错误 不调用就不会出错,一调用就出错
函数名指向函数体的内存地址
print(变量名)------> 被处理 ----- 显示内存地址存放的值 不能在加()
print(函数名)------> 没处理 ------ 显示值所在内存的地址 加()进行处理
函数名—>内存地址 + ()----> 函数可以加括号是语法定义的,找到内存地址处理代码得到结果
def aa():
print(1)
print(aa) # <function aa at 0x00000000012F70D0>
将函数内存地址引用给其他变量
def aa():
print(1)
bb = aa # 内存地址给 bb 这是一个没有被处理的程序
bb() # 加上括号,找到内存地址处理代码得到结果
# 显示为 1
函数的 参数 与 返回值取 取决于是否需要对函数传入值,和需要返回值。
定义函数的三种类型
# 无参 --------> 不需要传入值
def aa():
x = 10
y = 10
print(x + y)
# 有参 --------> 需要传入值
def bb(x,y):
print(x + y)
bb(10, 10)
# 空函数
def cc():
pass # 第一种, 兼容python 2
def dd():
... # 第二种
调用函数的三种格式
def aa():
return 123
aa() # 直接调用
res = aa() * 10 # 表达式
print(aa( )) # 作为其他函数的参数
返回值 return
一个函数中可以有多个return,只要执行一次,立刻结束当前所在函数,并将return 后的值设置为函数的返回值
1.return 值 # 返回单个值
2.return 值1,值2,值3 # 返回多个值(元组类型)
3.return 或 return None 或 不写 # 没有返回值,默认返回为None
# 返回单个值
def aa():
return 1
print(aa()) # 1
# 返回多个值(元组类型)
def aa():
return 1, 2, 3
print(aa()) # (1, 2, 3)
# 没有返回值,默认返回为None
def aa():
return
print(aa()) # None
# 不写return
def aa():
pass
print(aa()) # None
# 返回值 赋值给 变量
def ee():
return 1, 2, 3
num1, num2, num3 = ee() # 解压赋值
# return 结束当前函数
def aa():
return
print(666)
def bb():
aa()
print(123)
bb() # 123
参数类型提示功能
函数的参数可以是任意类型但是,但传入的值不符合要求,就会报错
参数设置提示,:参数提示 -> 返回值提示
def 函数名 (参数1:int, 参数2:‘必须传入字符串’)-> “返回值是整型”
def aa(x: '传入字符串', y: '传入整型') -> '返回值为字符串':
z = x * y
return z
print(aa('asd', 5))
提示简单明了,修改后:
def aa(x:str, y: int) -> str
z = x * y
return z
print(aa('asd', 5))
实参 与 形参
形参:函数定义阶段,括号内指定的参数(变量名)
实参:函数调用阶段,括号内传入的值 (变量值)
函数调用阶段 —> 实参值绑定给形参名,函数调用完毕 ----> 解除绑定
def aa(x, y): # x, y 是形参
z = x + y
aa(10, 20) # 10, 20 是实参
a = 10
b = 20
aa(a, b) # a, b 是实参
位置形参 与 位置实参
定义函数阶段,按照从左到右的顺序依次定义的形参,称为位置参数
特点:形参必须被传值
在函数调用阶段,按照从左到右的顺序依次穿入的值,称为位置实参
特点:按顺序依次为形参赋值
def aa(x, y, z): # (不能多,不能少,一个萝卜一个坑)
print(x, y, z)
aa(1, 2, 3) # 实参的长度与形参相匹配
aa(3, 2, 1)
关键字实参
在函数调用阶段,按key = value 的格式传入值,称为关键字实参
特点:不用记住形参的顺序,可打乱顺序赋值
def bb(x, y, z): # 指定赋值
print(x, y, z)
bb(x=1,z=3,y=2) # 顺序可乱
bb(z=3,x=1,y=2)
位置实参与关键字实参在一起混用时:
1.关键字实参不能位置参数前
2.不能为同一个形参多次赋值
def aa(x, y, z):
print(x, y, z)
aa(x=1, 2, z=3) # 关键字 在 位置实参 前面
# SyntaxError: positional argument follows keyword argument
def aa(x, y, z):
print(x, y, z)
aa(1, 2, 3, z=3) # z 被赋值两次
# TypeError: aa() got multiple values for argument 'z'
默认形参
在函数定义阶段,为形参赋值,称为默认形参,如果传值,以实参值为准。
特点:定义阶段已经为形参赋值,在调用阶段可以不用为其传值
位置形参和默认形参混用
1.位置形参在前,位置实参在后面
2.默认形参只在函数定义阶段赋值一次
3.默认形参的值推荐指向不可变类型
def aa(x, y=2, z=3):
print(x, y, z)
aa(1) # 1 2 3
aa(1, 5, 6) # 1 5 6
aa() # 第一次调用函数,创建一个空列表,1被添加进y的列表内 [1]
aa() # 第二次调用函数,不在创建空列表,1被添加进原来的列表内 [1, 1]
aa() # 第三次调用函数,不在创建空列表,1被添加进原来的列表内 [1, 1, 1]
x = 100 # 申请一个内存空间 把值100放进去 绑定给 变量名 x
y = x # 将x 的内存空间地址给 y 引用 x y 同时指向 内存地址
x = 200 # 申请一个内存空间 把值200放进去 绑定给 变量名 x , 原来的绑定断开
print(y) # y 不受影响
a = [1, 2, 3] # 申请一个内存空间 把值[1, 2, 3]放进去 绑定给 变量名 a
b = a # 将a 的内存空间地址给 b 引用 a b 同时指向 内存地址
a = 200 # 申请一个内存空间 把值200放进去 绑定给 变量名 a , 原来的绑定断开
print(b) # b 不受影响
k = [1, 2, 3] # 申请一个内存空间 把值[1, 2, 3]放进去 绑定给 变量名 k
v = k # 将k 的内存空间地址给 v 引用 k v 同时指向 内存地址
k.append(200) # 在内存空间 把值200放进去
print(v) # b 受影响影响
# 一个使用场景,利用在不对z传值的情况下的利用
def aa(x, y, z=123): # z 值不变
if z == 123: # 每次都为123
z = {} # 在将{}空字典赋值给z
z[x] = y
print(z)
aa('西瓜', 5) # {'西瓜': 5}
aa('香蕉', 4.5) # {'香蕉': 4.5}
可变长参数 * 与 **
在位置形参中带 * : * 将溢出的位置实参汇总成元组,赋值给紧跟其后的变量
def aa(x, *y):
print(x, y)
aa(1) # 1 () 没有溢出就输出空元组
aa(1, 2) # 1 (2,)
aa(1, 2, 3) # 1 (2, 3)
在关键字形参中带 * *: ** 将溢出的位置实参汇总成字典,赋值给紧跟其后的变量
# 实参与形参值长度相等
def aa(x, **y): # 字典是无序的
print(x, y)
aa(1) # 1 {}
aa(1, a=1, b=2) # 1 {'a': 1, 'b': 2}
在实参中带* :* 能被for循环的 字符串 ,元组,列表等都使用
# 实参与形参值长度相等
def aa(x, y, z):
print(x, y, z)
aa(*[1, 2, 3]) # 1 2 3
aa(*'qwe') # q w e
在关实参中带 * *: ** key=value 类型
# 实参与形参值长度相等
def aa(x, y, z):
print(x, y, z)
aa(**{'x': 5, 'y': 4.5, 'z': 5.2})
混用
通常,将 * 赋值给 args
将 * * 赋值 给 kwargs
参数的长度 指定着 参数的个数 长度固定
可变长参数的长度不可以固定
# 位置形参 几乎用不上
def num(x, *y, z): # *y 后面的z 就不能能是位置形参,z在这为位置形参
print(x, y, z) # 通过位置实参,赋值给 z
num(10, 20, z=11) # 10 (20,) 11
混用,位置实参*args在前,位置实参 **kwargs 在后
def num(x, *y, **z):
print(x, y, z)
num(10, 20, **{'z': 1})
接收任意长度的的参数
def num(*x, **y):
x1, x2 = x # 元组的值解压给 x1 x2
y1, y2 = y.values() # 字典的值解压复制给 y1 y2
print(x1, x2, y1, y2) # 10 20 30 40
num(10, 20, **{'y': 30, 'a': 40})