Python入门篇-函数、参数及参数解构
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.函数概述
1>.函数的作用即分类
函数 数学定义:y=f(x) ,y是x的函数,x是自变量。y=f(x0, x1, ..., xn) Python函数 由若干语句组成的语句块、函数名称、参数列表构成,它是组织代码的最小单元 完成一定的功能
函数的作用 结构化编程对代码的最基本的封装,一般按照功能组织一段代码 封装的目的为了复用,减少冗余代码 代码更加简洁美观、可读易懂
函数的分类 内建函数,如max()、reversed()等 库函数,如math.ceil()等
2>.函数定义,调用
def语句定义函数 def 函数名(参数列表): 函数体(代码块) [return 返回值]
函数名就是标识符,命名要求一样 语句块必须缩进,约定4个空格 Python的函数没有return语句,隐式会返回一个None值 定义中的参数列表成为形式参数,只是一种符号表达,简称形参
调用 函数定义,只是声明了一个函数,它不会被执行,需要调用 调用的方式,就是函数名加上小括号,括号内写上参数 调用时写的参数是实际参数,是实实在在传入的值,简称实参
3>.定义一个add函数案例
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com """ 下面只是一个函数的定义,有一个函数叫做add,接收2个参数 计算的结果,通过返回值返回 调用通过函数名add加2个参数,返回值可使用变量接收 定义需要在调用前,也就是说调用时,已经被定义过了,否则抛NameError异常 函数是可调用的对象,callable() 看看这个函数是不是通用的?体会一下函数的好处 """ def add(x, y): result = x+y return result out = add(500,600) print(out) #以上代码执行结果如下: 1100
二.函数参数
1>.函数参数相关概述
参数调用时传入的参数要和定义的个数相匹配(可变参数例外) 位置参数 def f(x, y, z) 调用使用f(1, 3, 5) 按照参数定义顺序传入实参 关键字参数 def f(x, y, z) 调用使用f(x=1, y=3, z=5) 使用形参的名字来出入实参的方式,如果使用了形参名字,那么传参顺序就可和定义顺序不同 传参 f(z=None, y=10, x=[1]) f((1,), z=6, y=4.1) f(y=5, z=6, 2) #这种传入参数的方法是错误的 要求位置参数必须在关键字参数之前传入,位置参数是按位置对应的
2>.函数参数默认值
参数默认值(缺省值) 定义时,在形参后跟上一个值 def add(x=4, y=5): return x+y 测试调用add(6, 10) 、add(6, y=7) 、add(x=5) 、add()、add(y=7)、add(x=5, 6) 、add(y=8,4)、add(x=5, y=6)、add(y=5, x=6) 测试定义后面这样的函数def add(x=4,y) 作用 参数的默认值可以在未传入足够的实参的时候,对没有给定的参数赋值为默认值 参数非常多的时候,并不需要用户每次都输入所有的参数,简化函数调用 举例 定义一个函数login,参数名称为host、port、username、password
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com def login(host='127.0.0.1',port='8080',username='yinzhengjie',password='yinzhengjie520'): print('主机IP:端口@用户名:密码 - {}:{}@{}/{}'.format(host, port, username, password)) login() login('127.0.0.1', 80, 'yzj', 'yinzhengjie') login('127.0.0.1', username='root') login('localhost', port=80,password='com') login(port=80, password='jason', host='www') #以上代码执行结果如下: 主机IP:端口@用户名:密码 - 127.0.0.1:8080@yinzhengjie/yinzhengjie520 主机IP:端口@用户名:密码 - 127.0.0.1:80@yzj/yinzhengjie 主机IP:端口@用户名:密码 - 127.0.0.1:8080@root/yinzhengjie520 主机IP:端口@用户名:密码 - localhost:80@yinzhengjie/com 主机IP:端口@用户名:密码 - www:80@yinzhengjie/jason
3>.可变参数
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com """ 可变参数 一个形参可以匹配任意个参数 """ def add(nums): sum = 0 for x in nums: sum += x return sum print(add([1,3,5])) #传入列表,可迭代 print(add((2,4,6,8,10,12,14,16,18,20))) #传入元组,可迭代 print(add([x for x in range(101)])) #列表解析式,可迭代 print(add((x for x in range(1010)))) #迭代器,可迭代 #以上代码执行结果如下: 9 110 5050 509545
4>.位置参数的可变参数
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com """ 在形参前使用*表示该形参是可变参数,可以接收多个实参 收集多个实参为一个tuple,因此我们不能像之前传入生成器或者列表解析式啦! """ def add(*nums): sum = 0 print(type(nums)) for x in nums: sum += x print(sum) print(add(1,3,5,7,9)) #以上代码执行结果如下: <class 'tuple'> 25 None
5>.关键字参数的可变参数
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com """ 形参前使用**符号,表示可以接收多个关键字参数 收集的实参名称和值组成一个字典 """ def showconfig(**kwargs): for k,v in kwargs.items(): print('{} = {}'.format(k, v)) showconfig(host='127.0.0.1',port='8080',username='jason',password='yinzhengjie') #以上代码执行结果如下: host = 127.0.0.1 port = 8080 username = jason password = yinzhengjie
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com def showconfig(username,*args,**kwargs): print(username) print(args) for k,v in kwargs.items(): print('{} = {}'.format(k,v)) showconfig("jason",1,2,3,x=100,y=200) #以上代码执行结果如下: jason (1, 2, 3) x = 100 y = 200
6>.可变参数总结
有位置可变参数和关键字可变参数 位置可变参数在形参前使用一个星号* 关键字可变参数在形参前使用两个星号** 位置可变参数和关键字可变参数都可以收集若干个实参,位置可变参数收集形成一个tuple,关键字可变参数收集形成一个dict 混合使用参数的时候,可变参数要放到参数列表的最后,普通参数需要放到参数列表前面,位置可变参数需要在关键字可变参数之前
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com def fn(x, y, *args, **kwargs): print(x) print(y) print(args) print(kwargs) print("*" * 20 + "我是分隔符" + "*" * 20) fn(3,5,7,9,10,a=1,b='python') fn(3,5) fn(3,5,7) fn(3,5,a=1,b='python') #以上代码执行结果如下: 3 5 (7, 9, 10) {'a': 1, 'b': 'python'} ********************我是分隔符******************** 3 5 () {} ********************我是分隔符******************** 3 5 (7,) {} ********************我是分隔符******************** 3 5 () {'a': 1, 'b': 'python'} ********************我是分隔符********************
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com def fn(*args, x, y, **kwargs): print(x) print(y) print(args) print(kwargs) print("*" * 20 + "我是分隔符" + "*" * 20) # fn(3,5,7) #报错:TypeError: fn() missing 2 required keyword-only arguments: 'x' and 'y' # fn(3,5,a=1,b='python') #报错:TypeError: fn() missing 2 required keyword-only arguments: 'x' and 'y' fn(7,9,y=5,x=3,a=1,b='python')
7>.keyword-only参数
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com """ keyword-only参数(Python3加入) 如果在一个星号参数后,或者一个位置可变参数后,出现的普通参数,实际上已经不是普通的参数了,而是keyword-only参数. """ def fn(*args, x): #args可以看做已经截获了所有的位置参数,x不使用关键字参数就不可能拿到实参 print(x) print(args) # fn(3,5,7) #报错:TypeError: fn() missing 1 required keyword-only argument: 'x' fn(3,5,x=7) #x的值需要使用关键字传参的方式传入 #以上代码执行结果如下: 7 (3, 5)
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com """ 需要注意的是: def(**kwargs, x): print(x) print(kwargs) 以上定义会直接报语法错误,可以理解为kwargs会截获所有的关键字参数,就算你写了x=5,x也永远得不到这个值,所以语法错误 """ def fn(*, x,y): #"*"号之后,普通形参都变成了必须给出的keyword-only 参数 print(x,y) fn(x=50,y=60) #以上代码执行结果如下: 50 60
8>.可变参数和参数默认值
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com def fn(*args, x=5): print(x) print(args) print("*" * 20 + "我是分隔符" + "*" * 20) fn() # 等价于fn(x=5) fn(5) fn(x=6) fn(1,2,3,x=10) #以上代码执行结果如下: 5 () ********************我是分隔符******************** 5 (5,) ********************我是分隔符******************** 6 () ********************我是分隔符******************** 10 (1, 2, 3) ********************我是分隔符********************
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com def fn(y, *args, x=5): print('x={}, y={}'.format(x, y)) print(args) print("*" * 20 + "我是分隔符" + "*" * 20) # fn() #报错:TypeError: fn() missing 1 required positional argument: 'y' fn(5) # fn(x=6) #报错:TypeError: fn() missing 1 required positional argument: 'y' fn(1,2,3,x=10) # fn(y=17,2,3,x=10) #报错:SyntaxError: positional argument follows keyword argument,因为要求位置参数必须在关键字参数之前传入 # fn(1,2,y=3,x=10) #报错:TypeError: fn() got multiple values for argument 'y',因为重复给y复制啦! #以上代码执行结果如下: x=5, y=5 () ********************我是分隔符******************** x=10, y=1 (2, 3) ********************我是分隔符********************
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com def fn(x=5, **kwargs): print('x={}'.format(x)) print(kwargs) print("*" * 20 + "我是分隔符" + "*" * 20) fn() fn(5) fn(x=6) # fn(y=3,x=10) fn(3,y=10) #以上代码执行结果如下: x=5 {} ********************我是分隔符******************** x=5 {} ********************我是分隔符******************** x=6 {} ********************我是分隔符******************** x=10 {'y': 3} ********************我是分隔符******************** x=3 {'y': 10} ********************我是分隔符********************
9>.参数规则
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com """ 参数列表参数一般顺序是,普通参数、缺省参数、可变位置参数、keyword-only参数(可带缺省值)、可变关键字参数。 def fn(x, y, z=3, *arg, m=4, n, **kwargs): print(x,y,z,m,n) print(args) print(kwargs) 需要注意的是: 代码应该易读易懂,而不是为难别人 请按照书写习惯定义函数参数 """ def connect(host='node101.yinzhengjie.org.cn', port='3306', user='admin', password='admin', **kwargs): print(host, port) print(user, password) print(kwargs) print("*" * 20 + "我是分隔符" + "*" * 20) connect(db='cmdb') connect(host='192.168.1.123', db='cmdb') connect(host='192.168.1.123', db='cmdb', password='mysql') #以上代码执行结果如下: node101.yinzhengjie.org.cn 3306 admin admin {'db': 'cmdb'} ********************我是分隔符******************** 192.168.1.123 3306 admin admin {'db': 'cmdb'} ********************我是分隔符******************** 192.168.1.123 3306 admin mysql {'db': 'cmdb'} ********************我是分隔符********************
10>.参数解构
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com """ 参数解构 给函数提供实参的时候,可以在集合类型前使用*或者**,把集合类型的结构解开,提取出所有元素作为函数的实参 非字典类型使用*解构成位置参数 字典类型使用**解构成关键字参数 提取出来的元素数目要和参数的要求匹配,也要和参数的类型匹配 """ def add(x, y): print(x+y) print("*" * 20 + "我是分隔符" + "*" * 20) add(*(1,2)) add(*[3,4]) add(*{5,6}) d = {'x': 7, 'y': 8} add(**d) add(**{'x': 10, 'y': 20}) # add(**{'a': 5, 'b': 6}) #报错:TypeError: add() got an unexpected keyword argument 'a' add(*{'a': 100, 'b': 200}) #以上代码执行结果如下: 3 ********************我是分隔符******************** 7 ********************我是分隔符******************** 11 ********************我是分隔符******************** 15 ********************我是分隔符******************** 30 ********************我是分隔符******************** ab ********************我是分隔符********************
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com def add(x, y): print(x+y) print("*" * 20 + "我是分隔符" + "*" * 20) add(1, 2) # add((4,5)) #报错:TypeError: add() missing 1 required positional argument: 'y' t = (3, 4) add(t[0], t[1]) add(*t) add(*(5,6)) add(*[7,8]) add(*{9,10}) add(*range(1,3)) #以上代码输出结果如下: 3 ********************我是分隔符******************** 7 ********************我是分隔符******************** 7 ********************我是分隔符******************** 11 ********************我是分隔符******************** 15 ********************我是分隔符******************** 19 ********************我是分隔符******************** 3 ********************我是分隔符********************
11>.参数解构和可变参数
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com """ 参数解构和可变参数 给函数提供实参的时候,可以在集合类型前使用*或者**,把集合类型的结构解开,提取出所有元素作为函数的实参 """ def add(*iterable): result = 0 for x in iterable: result += x print(result) print("*" * 20 + "我是分隔符" + "*" * 20) add(1,2,3) add(*[10,20,30]) add(*range(10)) #以上代码执行结果如下: 6 ********************我是分隔符******************** 60 ********************我是分隔符******************** 45 ********************我是分隔符********************
12>.小试牛刀
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com """ 编写一个函数,能够接受至少2个参数,返回最小值和最大值 """ def Comparing_size_of_two_numbers(a,b): print("最大值为:{}".format(max(a,b))) print("最小值为:{}".format(min(a,b))) print("*" * 20 + "我是分隔符" + "*" * 20) Comparing_size_of_two_numbers(10,20) Comparing_size_of_two_numbers(6,9) #以上代码执行结果如下: 最大值为:20 最小值为:10 ********************我是分隔符******************** 最大值为:9 最小值为:6 ********************我是分隔符********************
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com import random """ 编写一个函数,能够接受至少2个参数,返回最小值和最大值 """ def Comparing_size_of_two_numbers(*nums): print(nums) return max(nums),min(nums) print(*Comparing_size_of_two_numbers(*[random.randint(10,20) for _ in range(10)])) print("*" * 20 + "我是分隔符" + "*" * 20) print(Comparing_size_of_two_numbers(*[random.randint(10,20) for _ in range(10)])) #以上代码执行结果如下: (13, 20, 16, 16, 11, 19, 19, 19, 15, 20) 20 11 ********************我是分隔符******************** (19, 20, 13, 16, 19, 10, 20, 20, 12, 14) (20, 10)
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :yinzhengjie #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ #EMAIL:y1053419035@qq.com """ 编写一个函数,接受一个参数n,n为正整数,左右两种打印方式。要求数字必须对齐 1 12 11 10 9 8 7 6 5 4 3 2 1 2 1 11 10 9 8 7 6 5 4 3 2 1 3 2 1 10 9 8 7 6 5 4 3 2 1 4 3 2 1 9 8 7 6 5 4 3 2 1 5 4 3 2 1 8 7 6 5 4 3 2 1 6 5 4 3 2 1 7 6 5 4 3 2 1 7 6 5 4 3 2 1 6 5 4 3 2 1 8 7 6 5 4 3 2 1 5 4 3 2 1 9 8 7 6 5 4 3 2 1 4 3 2 1 10 9 8 7 6 5 4 3 2 1 3 2 1 11 10 9 8 7 6 5 4 3 2 1 2 1 12 11 10 9 8 7 6 5 4 3 2 1 1 """ def show(n): tail = " ".join([str(i) for i in range(n,0,-1)]) width = len(tail) for i in range(1,n): print("{:>{}}".format(" ".join([str(j) for j in range(i,0,-1)]),width)) print(tail) def showtail(n): tail = " ".join([str(i) for i in range(n,0,-1)]) print(tail) #无需再次生成列表 for i in range(len(tail)): if tail[i] == " ": print(" " * i,tail[i+1:]) show(12) print("*" * 20 + "我是分隔符" + "*" * 20) showtail(12) #以上代码输出结果如下: 1 2 1 3 2 1 4 3 2 1 5 4 3 2 1 6 5 4 3 2 1 7 6 5 4 3 2 1 8 7 6 5 4 3 2 1 9 8 7 6 5 4 3 2 1 10 9 8 7 6 5 4 3 2 1 11 10 9 8 7 6 5 4 3 2 1 12 11 10 9 8 7 6 5 4 3 2 1 ********************我是分隔符******************** 12 11 10 9 8 7 6 5 4 3 2 1 11 10 9 8 7 6 5 4 3 2 1 10 9 8 7 6 5 4 3 2 1 9 8 7 6 5 4 3 2 1 8 7 6 5 4 3 2 1 7 6 5 4 3 2 1 6 5 4 3 2 1 5 4 3 2 1 4 3 2 1 3 2 1 2 1 1