Python函数
- 由若干语句组成的语句块、函数名称、参数列表构成,它是组织代码的最小单元
- 完成一定的功能
- 函数也是一个对象
函数的作用
- 结构化编程对代码的最基本的封装,一般按照功能组织一段代码
- 封装的目的为了复用,减少冗余代码
- 代码更加简洁美观、可读易懂
函数的分类
- 内建函数,如max()、reversed()等
- 库函数,如math.ceil()等
函数的定义、调用
- 函数的定义
- def语句定义函数
def 函数名(参数列表):
函数体(代码块)
[return 返回值] - 函数名就是标识符,命名要求一样
- 语句块必须缩进,约定4个空格
- Python的函数可以没有return语句,如果没有,隐式会返回一个None值;return语句也不一定放在最后
- 定义中的参数列表成为形式参数,只是一种符号表达,简称形参,可以类似地理解为占位符一样的存在
- def语句定义函数
- 函数的调用
- 函数定义,只是声明了一个函数,它不会被执行,需要调用
- 定义需要在调用前,也就是说调用时,已经被定义过了,否则抛NameError异常
- 调用的方式,就是函数名加上小括号,括号内写上参数
- 函数是可调用的对象,判断是否可调用:callable()
- 调用时写的参数是实际参数,是实实在在传入的值,简称实参
函数参数
- 在函数定义时,形参有两种形式:位置参数和可变参数
- 位置参数
- 定义函数def(x, y, x),调用使用f(1, 2, 3),这种函数定义和调用时使用的参数叫做位置参数
- 按照形参定义的顺序一个一个匹配传入实参
- 如果函数定义的时候,形参的部分不是可变参数,那么这部分参数就是位置参数
- 关键字参数
- 定义函数 def(x, y, z),调用使用f(x=1, y=2, z=3),这种调用时使用的参数叫做关键字参数
- 使用形参的名字来传入实参的方式,如果使用了形参的名字,那么传参顺序就可以和定义的顺序不同
- 传参
- 在函数调用实参传参的时候要求:位置参数必须在关键字参数之前传入,位置参数是按位置对应的
- f(z=None, y=10, x=[1])
- f((1, ), z=6, y=4.1
- f(y=5, z=6, 2) # 这种写法是绝对错误的
- 函数定义时形参的默认值
- 定义时,在形参后跟上一个值
- 定义时,这部分形参如果不是可变参数,那么还是位置参数,只不过是多了一个默认值
- 参数的默认值可以在未传入足够的实参的时候,对没有给定的参数赋值为默认值
- 参数非常多的时候,并不需要用户每次都输入所有的参数,简化函数调用
- 定义函数的时候,没定义缺省值的形参要放在定义缺省值的前面
-
def add(x=4, y=5): return x+y # 测试调用 print(add()) # '''输出:9''' print(add(6)) # 6是位置参数,按顺序将6传参给x;y没传参,取缺省值 '''输出:11''' print(add(y=6)) # x没传参,取默认值4;y=6是关键字参数,将6传参给y '''输出:10''' # print(add(6, y=7)) # 6是位置参数,7是关键字参数 '''输出:13''' add(6, 10) # '''输出:16'''
-
# 定义一个函数login,参数名称为host、port、username、password def login(host, password, port=22, username='root', ): return '{}@{}:{} --password {}'.format(username, host, port, password) print(login('127.0.0.1', 'root_passwd', 23)) print(login('127.0.0.1', 'barry_passwd', username='barry')) '''输出: root@127.0.0.1:23 --password root_passwd barry@127.0.0.1:22 --password barry_passwd '''
可变参数
- 位置参数的可变参数
- 在函数定义时,形参前使用*表示该形参是位置参数的可变参数,可以接收多个实参 ,*形参就是一个标识符
- 如果函数定义时,形参中包含了位置参数的可变参数,要么不给它传参,要么在函数调用传参的时候使用位置参数给这部分形参进行传参
- 收集多个实参为一个tuple
-
def add(*nums): print(nums, type(nums)) sum = 0 for i in nums: sum += i return sum print(add(5, 6, 7)) print('~~~~~~') print(add()) '''输出: (5, 6, 7) <class 'tuple'> 18 ~~~~~~ () <class 'tuple'> 0 '''
- 关键字参数可变参数
- 在函数定义时,形参前使用**符号,表示可以接收多个关键字参数
- 如果在函数定义的时候,形参部分包含了关键字参数的可变参数,要么不它传参,要么在函数调用传参的时候使用关键字参数给这部分形参进行传参
- 收集的实参名称和值组成一个字典
-
def showconfig(**kwargs): print(kwargs) for k, v in kwargs.items(): print( '{} = {}'.format(k, v)) showconfig(host='127.0.0.1', port=22, username='root', password='root_passwd') '''输出: {'host': '127.0.0.1', 'port': 22, 'username': 'root', 'password': 'root_passwd'} host = 127.0.0.1 port = 22 username = root password = root_passwd '''
- 两种可变参数混合使用
- 混合参数在函数定义时的使用原则:
- 形参中,位置可变参数需要在关键字可变参数之前 -
def fn(x, y, *args, **kwargs): print(x) print(y) print(args) print(kwargs) fn(3,5,7,9,10,a=1,b='barry') print('~~~~~~') fn(3,5) print('~~~~~~') fn(3,5,7) print('~~~~~~') fn(3,5,a=1,b='barry') print('~~~~~~') # fn(7,9,y=5,x=3,a=1,b='barry') # 错误:7和9分别赋给了x,y,又y=5、x=3,重复了,会抛TypeError: fn() got multiple values for argument 'y'异常 '''输出: 3 5 (7, 9, 10) {'a': 1, 'b': 'barry'} ~~~~~~ 3 5 () {} ~~~~~~ 3 5 (7) {} ~~~~~~ 3 5 () {'a': 1, 'b': 'barry'} ~~~~~~ TypeError: fn() got multiple values for argument 'y' '''
- 混合参数在函数定义时的使用原则:
keyword-only参数(Python3加入)
- 函数定义时候,如果可变参数后面定义了位置参数,那么给这部分位置参数进行传参的时候,必须使用关键字参数进行传参,如果这部分位置参数有默认值,可以不传参,使用默认值
- 如果在函数定义时的形参中,使用了*,那么在表示在*后必须使用keyword-only参数,*只是作为强制使用keyword-only参数的符号,不是形参
- args可以看做截获了所有的位置参数,后面的形参如果不使用关键字进行传参,就不能拿到实参
-
def fn(*args, x): print(x) print(args) '''fn(3, 5)''' # 抛异常:TypeError: fn() missing 1 required keyword-only argument: 'x' '''# fn(3, 5, 7)''' # 抛异常:TypeError: fn() missing 1 required keyword-only argument: 'x' fn(3, 5, x=7) '''输出: 7 (3, 5) '''
可变参数和默认值
-
def fn(x=5, **kwargs) # 因为x=5在函数定义时使用的是位置参数定义,只不过是多了一个默认值,所以在函数调用传参的时候可以使用位置参数传参,也可以使用关键字参数传参,只要找到x传参了就行,没找到就使用默认值 print(x) print(kwargs) print(y=7, x=4) '''输出: 4 {'y': 7} '''
参数的规则
- 形参列表的参数一般顺序是:普通参数、缺省参数、可变位置参数、keyword-only参数(可带缺省值)、可变关键字参数
-
def fn(x, y, z=3, *arg, m=4, n, **kwargs): print(x,y,z,m,n) print(args) print(kwargs)
参数的解构
- 给函数提供实参的时候,可以在集合类型前使用*或者**,把集合类型的结构解开,提取出所有的元素
- 元素作为函数的实参
- 非字典类型使用*解构成位置参数
- 字典类型使用**解构成关键字参数
- 提取出来的元素数目要和参数的要求匹配,也要和参数的类型匹配
-
def add(x, y): return x+y print(add(*(4, 5))) print(add(*[4, 5])) print(add(*{4, 5})) print(add(**{'x':4, 'y':5})) '''输出: 9 9 9 9 '''
-
def sum_1(*args, **kwargs): result = 0 for i in args: result += i return i print(sum_1(*range(5))) print(add(*[1, 2, 3, 4, 5, 6])) '''输出: 10 21 '''