函数
一、引入
二、定义函数
作用:提高编写效率,代码重复利用 代码简洁 方便修改,更易扩展 保持代码的一致性
三种定义方式:
1.无参函数 2. 有参函数 3. 空函数
三、函数调用
1. 语句的形式:只加括号调用
2. 表达式:
3. 函数调用可以当参数
四、函数返回值
1. 没有return或者return 或者return None ===> 返回None
2. 返回一个值:return x
3. 返回多个值,逗号分隔开,返回的是一个元组: return 1,3,5
五、函数的参数
python中所有值的传递,传递的都不是值的本身,而是值的引用,即内存地址
形参:定义时的参数,也是局部变量
实参:调用的传参值
位置参数:一个萝卜一个坑,不能多不能少,位置一一对应
默认参数:函数定义时,调用时能少写实参,放在位置参数后面
定义默认参数时,必须是不可变类型
可变类型的默认参数,在函数内部修改,默认参数也会修改
关键字参数:
函数调用,key=value不用按照顺序书写,放在位置参数后面
可变参数:*args,**kwargs。分别是元组 和 字典
命名关键字参数:没有可变参数时候,前面要用*占坑。
传参时,书写要key=value的格式
顺序书写:位置参数,默认参数,可变参数,命名关键字参数
一、引入
比如一个修理工会事先准备好螺丝刀、锤子等工具,这样在进行修理的过程中,需要用到拧螺丝的功能时就直接拿来螺丝刀使用,需要用到锤击物体的功能时就直接拿来锤子使用,而无需临时制造。这个例子的核心在于’事先准备好工具’,遇到应用场景时’拿来就用’,。
在程序中,具备某一功能的‘工具’指的就是函数,‘事先准备工具’的过程即函数的定义,‘拿来就用’即函数的调用。
二、定义函数
1.定义
# 定义
def 函数名(参数名1,参数名2):
"""文档字符串"""
# 函数体
return 表达式
def add(x:int, y:int) -> int: # x,y为int型,函数返回为int型,只是注释,参数格式非法不会报错
pass
return x+y
-
def: 定义函数的关键字;
-
函数名:函数名指向函数内存地址,是对函数体代码的引用。函数的命名应该反映出函数的功能;
-
括号:括号内定义参数,参数是可有可无的,且无需指定参数的类型;
-
冒号:括号后要加冒号,然后在下一行开始缩进编写函数体的代码;
-
"""文档字符串""": 描述函数功能,参数介绍等信息的文档,非必要,但是建议加上,从而增强函数的可读性;
-
函数体:由语句和表达式组成;
-
return 值:定义函数的返回值,return是可有可无的。
函数的作用
.为什么使用函数:
1.不适用函数: 组织结构不清晰,可毒性差
2.代码冗余
3.可维护性、扩展性差
作用:
提高编写效率,代码重复利用
代码简洁
方便修改,更易扩展
保持代码的一致性
2.三种定义方式:
形式一:无参函数
def func():
print("无参数函数")
# 调用
func()
# 定义函数发生的事情
# 1. 将申请内存空间保存函数体代码
# 2. 将上诉内存地址绑定给函数名
# 3. 定义时不会执行函数体代码,但是检测代码语法。只有调用时才会执行函数代码
# 调用函数发生的事情
print(func) # <function func at 0x0000000002936488>
# 1. 通过函数名找到函数的内存地址
# 2. 然后加括号就是在触发函数体代码的执行
func()
# 示范1
def bar(): # 函数定义会检测函数体代码语法
print("i am adeng")
def foo(): # 函数定义会检测函数体代码
bar()
print("阿登")
foo() # 调用时才会执行函数代码
# 示范2
def foo():
bar()
print("阿登")
def bar():
print("i am adeng")
foo()
# 示范3
def foo():
bar()
print("阿登")
foo() # 会报错 调用时报错,因为函数体中的代码bar() 找不到这个函数
def bar():
print("i am adeng")
形式2:有参函数
# 形式2:有参函数
# 如果把函数比喻成一个工厂,那么参数就是原材料,返回值是产品
def func(x,y): # x,y 材料
return x+y # 产品
func(1,2) # 1传给x 2传给y,位置参数 一一对应
print(func.__doc__)
形式3:空函数
# 形式三:空函数
def func():
pass # 占位符
func()
# 构思代码的时候使用 空函数
三、函数调用
1. 语句的形式:只加括号调用
def foo():
print("adneg")
def add(x,y):
return x+y
foo()
2. 表达式:
# 赋值表达式
res = add(1,2)
print(res)
# 数学表达式
res = add(1,2)*10
print(res)
3.函数调用可以当参数
res1= add(1,add(1,2))
print(res1)
四、函数返回值
-
没有return或者return 或者return None ===> 返回None
-
返回一个值:return x
-
返回多个值,逗号分隔开,返回的是一个元组: return 1,3,5
# 函数体代码一旦运行到return会立刻终止函数的运行。
def add(x,y):
print('111')
return x+y # return下面代码不会执行
print("222")
res = add(1,2)
# 1 没有return或者return 或者return None ===> 返回None
# 2 返回一个值:return x
# 3.返回多个值,逗号分隔开,返回的是一个元组: return 1,3,5
五、函数参数
形参:定义时的参数,也是局部变量
实参:调用的传参值
位置参数:一个萝卜一个坑,不能多不能少,位置一一对应
默认参数:函数定义时,调用时能少写实参,放在位置参数后面
定义默认参数时,必须是不可变类型
可变类型的默认参数,在函数内部修改,默认参数也会修改
关键字参数:
函数调用,key=value不用按照顺序书写,放在位置参数后面
可变参数:*args,**kwargs。分别是元组 和 字典
命名关键字参数:没有可变参数时候,前面要用*占坑。
传参时,书写要key=value的格式
顺序书写:位置参数,默认参数,可变参数,命名关键字参数
image.png
默认参数
1.默认参数的值在函数定义阶段被赋值的,被赋值的是内存地址
2.python中所有值的传递,传递的都不是值的本身,而是值的引用,即内存地址
# python中所有值的传递,传递的都不是值的本身,而是值的引用,即内存地址
m =2
def dunc(x,y=m): # y=> 2的内存地址
print(x,y)
m =3
func(1) # print(1,2) 不是print(1,3)
2.虽然默认值可以被指定为任意类型,但是不推荐使用可变类型
# 默认参数是可变类型
# 默认参数必须在位置参数 右边
def foo(n, arg=[]): arg=> []的内存地址
arg.append(n)
return arg
print(foo(1)) # [1]
print(foo(2)) # [1, 2]
# 解决方案如下
def foo(n, arg=None):
if arg is None:
arg = []
arg.append(n)
return arg
print(foo(1)) # [1]
print(foo(2)) # [2]
3.函数定义时默认参数的位置必须放在位置参数后面
可变参数:*args,**kwargs分别是元组 和 字典
- 可变长度指的是在函数调用时,传入的值(实参)的个数不固定。
- 实参是用来为形参赋值,所以对应着,针对溢出的实参必须有对应的形参来接收
# *形参名:用来接收溢出的位置参数,溢出的位置实参会被*args接收,args是一个元组
def func(x,y,*z):
print(x,y,z)
func(1,2,3,4,5) # 1 2 (3, 4, 5)
l = 7,8
func(1,2,*l) # 1 2 (7, 8)
func(1,2,l) # 1 2 ((7, 8),)
# 求一个序列的和
def my_sum(*args):
res = 0
for i in args:
res +=i
return res
res = my_sum(1,2,4,7)
print(res) # 14
# **形参名:用来接收溢出的关键字实参,**会将溢出的关键字实参保存成字典,赋值给紧跟其后的形参名**kwargs.kwargs是一个字典
*args放在**kwargs前面
def func(x,y,**kwargs):
print(x,y,kwargs)
func(1,y=2,a=3,b=4,c=5) # 1 2 {'a': 3, 'b': 4, 'c': 5}
l = {"a":5,"b":8}
func(1,2,**l) # 1 2 {'a': 5, 'b': 8}
- 函数定义:
*和**是打包成一个元组和字典
- 函数调用:
*和** 是解包。 * 可以看成对迭代对象的for循环得到的位置参数。**是解包成key=value.
*和** 混用
def index(x,y,z):
print(x,y,z)
# 函数定义*和**是打包:*是实参位置参数打包成元组,**是实参关键字参数key=value打包成字典
def wrapper(*args,**kwargs):# args=(1,) kwargs ={"z":2,"y":3}
index(*args,**kwargs) # index(1,z=2,y=3) # 函数调用*和** 是解包
# index(*(1,),**{"z":2,"y":3})
# index(1,x=2,y=3)
wrapper(1,z=2,y=3) # 1 3 2
# 上面wrapper传参的格式,其实是受index函数的格式。
命名关键字参数 *
- 有可变参数 形参*args **kwargs时候 *可以胜率
- 没有 *保留
命名关键字实参 必须按照key=value的形式传参
def func(a,b,*,c,d):
print(a,b,c,d) # 1 2 3 4
func(1,2,c=3,d=4)
def bar(a,b,*args,c,d):
print(a,b,c,d) # 1 2 3 4
bar(1,2,5,6,7,c=3,d=4)
def my(a,*,b=4,c): # 这里c不是位置参数,是命名关键字参数,放在了位置参数a后面没有报错
print(a,b,c) # 1 4 22
my(1,c=22)
# 书写顺序 位置参数 默认参数 *args 命名关键字 **kwargs
def bar(a,b,*args,c,d,**kwargs): # **kwargs 放在命名关键字c,d之前会报错
print(a,b,c,d) # 1 2 3 4
bar(1,2,5,6,7,c=3,d=4)
网友评论