python之函数详述
目录
1.函数前言
1.1定义
函数是具有一定功能的代码容器。
1.2使用函数的好处
1.组织结构清晰,可读性增强
2.可重复使用,减少代码冗余
2.可扩展性提高
2.使用函数
将一段经常使用的代码封装成函数,在需时直接调用。
2.1使用规则
# 函数必须先定义后使用。
定义阶段:申请内存空间将函数体放进去,将内存地址绑定给函数名。
调用阶段:通过函数名得到函数体的地址,加上括号执行函数体代码。
定义阶段时只检测语法不执行代码,调用阶段才会执行函数体,逻辑错误才会被检查到。
2.2语法结构
def 函数名(参数1,···): # 函数的定义
"""
为函数说明
"""
代码1...
代码2...
return 值
函数名(参数1,参数2) # 调用阶段
2.3语法检测
# 函数定义阶段只检测语法
def func():
qwe # 语法上没有错误
# 运行程序 进程已结束,退出代码为 0
# 函数调用阶段解释代码并执行
func()
"""
NameError: name 'qwe' is not define
没有定义 qwe 逻辑错误 不调用就不会出错,一调用就出错
"""
3.变量名与函数名
3.1区别
变量名指向变量值的内存地址
函数名指向函数体的内存地址
print(变量名)------> 被处理 -----> 显示内存地址存放的值 不能在加()
print(函数名)------> 没处理 ------> 显示值所在内存的地址 加()进行处理
函数可以加括号是语法定义的
函数名---> 内存地址 +()----> ,找到内存地址处理代码得到结果
def aa():
print(1)
print(aa) # <function aa at 0x00000000012F70D0>
3.2引用函数
将函数内存地址引用给其他变量。
其他的函数加上括号可以调用函数。
def aa():
print(1)
bb = aa # 内存地址绑定给 bb 这是一个没有被处理的程序
bb() # 加上括号,找到内存地址处理代码得到结果
# 显示为 1
4.函数的类型
4.1分类
# 函数的三种类型:
1.无参函数 函数在定义阶段括号内没有参数
2.有参函数 函数在定义阶段括号内有参数
3.空函数 函数在定义阶段括号内没有参数,函数体为空(pass 或 ···)
# 函数的 参数 与 返回值 取决于是否需要对函数传入值与需要返回值。
4.2无参函数
# 无参 --------> 不需要传入值
def aa():
x = 10
y = 10
print(x + y)
aa()
4.3有参函数
# 有参 --------> 需要传入值
def bb(x,y):
print(x + y)
bb(10, 10)
4.4空函数
# 空函数
def cc():
pass # 第一种, 兼容python 2
cc()
def dd():
... # 第二种
dd()
4.5函数的调用
def aa():
return 123
aa() # 直接调用
res = aa() * 10 # 表达式
print(aa( )) # 作为其他函数的参数
5.函数返回值
5.1返回值
# 关键字 return
一个函数中可以有多个return,只要执行一次,立刻结束当前所在函数的运行,
并将return 后的值设置为函数的返回值。
1.没有 return 关键字 返回值 默认为None
2.只有 return 关键字 后面没有跟内容 返回默认值 默认为None
-->等同 return None
3.return 值 # 返回单个值
4.return 值1,值2,值3 # 返回多个值(元组类型)
# return 结束当前函数
def aa():
return # 直接结束函数的运行
print(666)
aa()
# 举例
def bb():
print(123) # 123
return
bb()
5.2不写return
def aa():
pass
print(aa()) # None
5.3只写return
def aa():
return
print(aa()) # None
5.3返回单个值
def aa():
return 1
print(aa()) # 1
5.4返回多个值
def aa():
return 1, 2, 3
print(aa()) # (1, 2, 3)
5.5获取多个返回值
# 返回值 赋值给 变量
def ee():
return 1, 2, 3
num1, num2, num3 = ee() # 解压赋值
6.参数类型提示
6.1设置说明
函数的参数可以是任意类型但是,但传入的值不符合要求,就会报错
参数设置提示,
:参数提示 -> 返回值提示
def 函数名 (参数1:int, 参数2:‘必须传入字符串’)-> “返回值是整型”
6.2文字说明
def aa(x: '传入字符串', y: '传入整型') -> '返回值为字符串':
z = x * y
return z
print(aa('asd', 5))
6.3简易提示
def aa(x:str, y: int) -> str:
z = x * y
return z
print(aa('asd', 5))
7.实参与形参
7.1定义
# 形参:函数定义阶段,括号内指定的参数(变量名)
def func(a, b): # a和b就是func的形参
pass
# 实参:函数调用阶段,括号内传入的值(变量值)
func(1, 2) # 数据1和2就是func的实参
# 两者之间的关系:
函数调用阶段 ----> 实参的值绑定给形参名
函数调用完毕 ----> 解除绑定
# 形参与实参的表现形式:
形参的表现形式只有一种就是变量名
实参的表现形式有很多种(但是把握核心 就是 数据值)
7.2实例
def aa(x, y): # x, y 是形参
z = x + y
aa(10, 20) # 10, 20 是实参
a = 10
b = 20
aa(a, b) # a, b 是实参
8.位置形参与位置实参
8.1定义
# 位置形参:定义函数阶段,按照从左到右的顺序依次定义的形参
特点:形参必须被传值
# 位置实参:在函数调用阶段,按照从左到右的顺序依次传入的值
特点:按顺序依次为形参赋值
# 举例:定义一个可以比较大小的函数(传入两个值,返回比较大的那个)
def my_max(a, b): # a,b即位置形参
print(a, b)
if a > b:
return a
else:
return b
res = my_max(111, 222) # 111,222 即为位置实参
print(res)
8.2实例
def aa(x, y, z): # (不能多,不能少,一个萝卜一个坑)
print(x, y, z)
aa(1, 2, 3) # 实参与形参的个数相匹配
aa(3, 2, 1)
9.关键字实参
9.1定义
# 关键字实参:在函数调用阶段,按 key = value 的格式传入值
特点:不用记住形参的顺序,可打乱顺序赋值
# 举例:
def my_max(a, b):
print(a, b)
if a > b:
return a
else:
return b
res1 = my_max(a=222, b=111)
print(res1)
9.2实例
def bb(x, y, z): # 指定赋值
print(x, y, z)
bb(x=1,z=3,y=2) # 顺序可乱
bb(z=3,x=1,y=2)
9.3混用
# 位置实参与关键字实参在一起混用时:
1.关键字实参不能位置参数前
2.不能为同一个形参多次赋值
# 记忆口诀:越简单的格式写在前面,越复杂的格式写在后面
# 例子1
def aa(x, y, z):
print(x, y, z)
aa(x=1, 2, z=3) # 关键字 在 位置实参 前面
# SyntaxError: positional argument follows keyword argument
# 例子2
def aa(x, y, z):
print(x, y, z)
aa(1, 2, 3, z=3) # z 被赋值两次
# TypeError: aa() got multiple values for argument 'z'
10.默认形参
10.1定义
# 在函数定义阶段,为形参赋值,称为默认形参,如果传值,以实参值为准。
特点:定义阶段已经为形参赋值,在调用阶段可以不用为其传值
# 位置形参和默认形参混用:
1.位置形参在前,位置实参在后面
2.默认形参只在函数定义阶段赋值一次
3.默认形参的值推荐指向不可变类型
def register(name, age, sex='male'): # 默认形参性别男
print('%s:%s:%s' % (name, age, sex))
register('jason', 18) # 默认形参在调用阶段不给值就使用默认值
register('tony', 20)
register('lili', 19, 'female') # 默认形参在调用阶段也可以给值,给值就用值
10.2使用场景
# 默认参数使用场景
def func(name, age, gender='male'):
print(name, age, gender)
func('kid', 18)
func('qz', 19)
func('qq', 19, 'female')
# 在不对z传值的情况下的利用
def func(key, value, is_dict=True):
if is_dict: # is_dict值不变
dic = {} # dic 为一个空字典
dic[key] = value
print(dic)
func('西瓜', 15)
11.注意点
11.1共用空间
# 关键字参数为一个空的列表。
def aa(x=[]):
x.append(1)
print(x)
aa() # 第一次调用函数,创建一个空列表,1被添加进y的列表内 [1]
aa() # 第二次调用函数,不在创建空列表,1被添加进原来的列表内 [1, 1]
aa() # 第三次调用函数,不在创建空列表,1被添加进原来的列表内 [1, 1, 1]
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) # v 也更随着变量
11.2值的引用
x = 100 # 申请一个内存空间 把值100放进去 绑定给 变量名 x
y = x # 将x 的内存空间地址给 y 引用, x y 同时指向 内存地址
def func():
print(y) # y 不受影响
x = 200 # 申请一个内存空间 把值200放进去 绑定给 变量名 x , 原来的绑定断开
func()
12.可变长参数
12.1*与**
# 在位置形参中带 *
* 将溢出的位置实参汇总成元组,赋值给紧跟其后的变量。
# 在关键字形参中带 **
** 将溢出的位置实参汇总成字典,赋值给紧跟其后的变量。
12.2*的使用
def aa(x, *y):
print(x, y)
aa(1) # 1 () 没有溢出就输出空元组
aa(1, 2) # 1 (2,)
aa(1, 2, 3) # 1 (2, 3)
12.3**的使用
# 实参与形参值长度相等
def aa(x, **y): # 字典是无序的
print(x, y)
aa(1) # 1 {}
aa(1, a=1, b=2) # 1 {'a': 1, 'b': 2}
12.4实参中使用
# 在实参中带*
* 能被for循环的 字符串 ,元组,列表等都使用
在关实参中带 **:** key=value 类型
# 实参与形参值长度相等
def aa(x, y, z):
print(x, y, z)
aa(*[1, 2, 3]) # 1 2 3
aa(*'qwe') # q w e
# 实参与形参值长度相等
def aa(x, y, z):
print(x, y, z)
aa(**{'x': 5, 'y': 4.5, 'z': 5.2})
12.5合用
# 约定俗成:
将 * 赋值给 args
将 ** 赋值 给 kwargs
参数的长度指定参数的个数,长度固定。
可变长参数的长度不固定。
(*args, **kwargs)接收任意长度的的参数。
def num(*args, **kwargs):
x1, x2 = args # 元组的值解压给 x1 x2
y1, y2 = kwargs # 字典的值解压复制给 y1 y2
print(x1, x2, y1, y2) # 10 20 30 40
num(*(10, 20), **{'y': 30, 'a': 40})
12.6混用
# 混用,位置实参*args在前,位置实参 **kwargs 在后。
def num(x, *args, **kwargs):
print(x, args, kwargs)
num(10, *(20, 30), **{'西瓜': 1})
13.命名关键字参数(基本不用)
# 在位置参数形参后面看起来像位置形参的参数。(自己不会这样去写代码,一般出现在面试题中)
# 几乎用不上
def num(x, *args, y): # *args 后面的y 就不能能是位置形参,y在这为命名关键字参数
print(x, args, y) # 通过位置实参,赋值给 y
num(10, *(20, 30), y=40) # 10 (20, 30) 40