本文共 7322 字,大约阅读时间需要 24 分钟。
python里有很多的内置函数给我们的工作带来了很多发便利,在我们实现某些功能或者优化代码的时候,可以自己定义一个函数,同时我们在定义一个类的时候也会用到函数的一些知识去构造一个方法,这里就涉及到一些关于函数的基础知识和函数传参的知识。
一、函数的相关介绍
1.函数定义:函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可。
函数特性:
减少重复代码
使程序变的可扩展
使程序变得易维护
2、函数的定义示例
定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | def echostr(): #用关键字def定义一个函数 print ( "Hello, world" ) echostr() #调用函数 结果: Hello, world def printstr(str1,str2,str3): return str1,str2,str3 #使用return返回参数 s = printstr( "mysql" , "1929" , "baidu" ) #对调用函数,初始化s对象 print (s) #打印s 结果: ( 'mysql' , '1929' , 'baidu' ) |
一般情况下,在函数中使用return语句,会返回一个参数,而上面的我们返回了三个参数,这时就会输出一个元组,
1 2 3 | print ( type (s)) < class 'tuple' > 输出结果验证为元组 |
函数定义小结
定义函数时,需要确定函数名和参数个数;
如果有必要,可以先对参数的数据类型做检查;
函数体内部可以用return随时返回函数结果;
函数执行完毕也没有return语句时,自动return None。
函数可以同时返回多个值,但其实就是一个tuple。
3、简单的传参式定义示例
下面的的示例中定义了3个参数a,b,c,在调用的过程中给传入mysql,1929,baidu三个参数分别给a,b,c.
1 2 3 4 5 6 7 | def printstr(a,b,c): print (a,b,c) printstr( "mysql" , "1929" , "baidu" ) 结果: mysql 1929 baidu |
4、函数参数与局部变量
在我们学习C语言之类的语言都会学过形参、实参的概念,而python里面也是存在形参和实参的概念。
形参变量 只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量。
实参变量 可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值。
默认参数:
在我们我们设计产品时,特别有好多的地方会显示一些默认值,当你未传入值时就会传入默认参数,传入和,默认参数不一样的值时会替代默认参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | def stuInfo(name,age,sex,address,telphone,shcool = "清华大学" ): print ( "The student name is:" ,name) print ( "The student age is:" , age) print ( "The student sex is:" , sex) print ( "The student address is:" , address) print ( "The student telphone is:" , telphone) print ( "The student shcool is:" , shcool) stuInfo( "linux" , 18 , "boy" , "北京" , "18393820785" ) #未传入默认参数shcool 执行结果: * * * * * * * * * * * * * * * * * * * * * * * * * * * * The First stuent info * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * The student name is : linux The student age is : 18 The student sex is : boy The student address is : 北京 The student telphone is : 18393820785 The student shcool is : 清华大学 stuInfo( "docker" , 2 , "girl" , "上海" , "NULL" , "上海交通大学" ) #传入和默认参数值不同的参数 执行结果: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * The Second stuent info * * * * * * * * * * * * * * * * * * * * * * * * * * * * * The student name is : docker The student age is : 2 The student sex is : girl The student address is : 上海 The student telphone is : NULL The student shcool is : 上海交通大学 |
默认参数注意点
一是必选参数(函数定义时所有的非默认参数)在前,默认参数在后,否则Python的解释器会报错(思考一下为什么默认参数不能放在必选参数前面);
传入变量时容易产生歧义,所以我们将默认参数放置在必选参数的最后,
二是如何设置默认参数。
当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数。
使用默认参数有什么好处?最大的好处是能降低调用函数的难度。
关键字参数
在上面的示例中,使用的是按照参数定义的顺序传入参数,当我们定义的参数比较多的时候,就容易混乱,有一个关键字参数这时候就比较适合这种情景,同时使用关键字参数就可以打乱我们传入参数的顺序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | def stuInfo(name,age,sex,address,telphone,shcool = "清华大学" ,): print ( "The student name is:" ,name) print ( "The student age is:" , age) print ( "The student sex is:" , sex) print ( "The student address is:" , address) print ( "The student telphone is:" , telphone) print ( "The student shcool is:" , shcool) stuInfo(name = "docker" ,age = 2 ,sex = "girl" ,address = "上海" ,telphone = "NULL" ) #使用定义函数的关键字 结果: The student name is : docker The student age is : 2 The student sex is : girl The student address is : 上海 The student telphone is : NULL The student shcool is : 清华大学 |
很明显,这样用关键字传入参数很清晰、明了,当我们排除异常和解决bug等都是比较好的方案。同时关键字参数还可以和我们定义的参数按照位置顺序(位置参数)结合使用,但是需要注意:关键参数必须放在位置参数之后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | stuInfo( "docker" , 2 ,sex = "girl" ,address = "上海" ,telphone = "NULL" ) 执行结果: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * The Second stuent info * * * * * * * * * * * * * * * * * * * * * * * * * * * * * The student name is : docker The student age is : 2 The student sex is : girl The student address is : 上海 The student telphone is : NULL The student shcool is : 清华大学 stuInfo(name = "docker" , 2 , "girl" , "上海" , "NULL" ) #关键字参数在位置参数前面调用 会报错 执行结果: stuInfo(name = "docker" , 2 , "girl" , "上海" , "NULL" ) ^ SyntaxError: positional argument follows keyword argument 执行报错 语法错误 关键字参数在位置参数的后面 |
注意点:
在定义函数、调用函数的过程中,必须记住,关键字参数必须放在位置参数的后面。
非固定参数*args
例如上面定义的函数,主要包含姓名、年龄、性别、家庭住址、手机号码、学校等信息,想要传入更多的参数,这时我们定义的参数就不能满足需求,这时我们就可以用非固定参数,在不确定他们传入多少个参数的时候就可以使用非固定参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | def stuInfo2( * args): print (xargs) return xargs stuInfo2( "docker" , " " , "girl" , "上海" , "NULL" ) 结果: ( 'docker' , ' ' , 'girl' , '上海' , 'NULL' ) 默认参数与非固定参数的结合 def stuInfo(name,age,sex,address,telphone,shcool = "清华大学" , * xargs): print ( "The student name is:" ,name) print ( "The student age is:" , age) print ( "The student sex is:" , sex) print ( "The student address is:" , address) print ( "The student telphone is:" , telphone) print ( "The student shcool is:" , shcool) print ( "非固定变量:" ,xargs) stuInfo( "docker" , 2 , "girl" , "上海" , "NULL" , "mysqlDBA" , "redis" , "python" , "java" ) |
非固定参数**kwargs
除了上面介绍的*args非固定参数外,还有一种非固定参数**kwargs,*kwargs 会把多传入的参数变成一个dict形式。
**kwargs 允许你将不定长度的键值对, 作为参数传递给一个函数。 如果你想要在一个函数里处理带名字的参数, 你应该使用**kwargs。
在函数中处理键值参数
1 2 3 4 5 6 7 8 9 | def greet_me( * * kwargs): for key, value in kwargs.items(): print ( "{0} == {1}" . format (key, value)) greet_me(name = "alibaba" ) #调用函数 greet_me(obc = "mysql" ) #调用函数 结果: name = = alibaba obc = = mysql |
1 2 3 4 5 6 | def stu_info(name,age, * args, * * kwargs): # *kwargs 会把多传入的参数变成一个dict形式 print (name,age,args,kwargs) stu_info( "jack" , 32 , "baidu" , "python" ,job1 = "mysqlDBA" ,job2 = "linux SRE" ) jack 32 ( 'baidu' , 'python' ) { 'job2' : 'linux SRE' , 'job1' : 'mysqlDBA' } |
*args参数结果是一个tuple型的
**kwargs参数结果是字典型,键值形式的。
组合参数
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | def f1(a, b, c = 0 , * args, * * kw): print ( 'a =' , a, 'b =' , b, 'c =' , c, 'args =' , args, 'kw =' , kw) def f2(a, b, c = 0 , * , d, * * kw): print ( 'a =' , a, 'b =' , b, 'c =' , c, 'd =' , d, 'kw =' , kw) f1( 1 , 2 ) f1( 1 , 2 ,c = 3 ) f1( 1 , 2 , 3 , "a" , "b" ) f1( 1 , 2 , 3 , 'a' , 'b' ,x = 99 ) f2( 1 , 2 ,d = 99 ,ext = None ) 结果: a = 1 b = 2 c = 0 args = () kw = {} a = 1 b = 2 c = 3 args = () kw = {} a = 1 b = 2 c = 3 args = ( 'a' , 'b' ) kw = {} a = 1 b = 2 c = 3 args = ( 'a' , 'b' ) kw = { 'x' : 99 } a = 1 b = 2 c = 0 d = 99 kw = { 'ext' : None } |
*xargs、**kwargs还通过一个tuple和dict,调用我们定义好的参数,例如
1 2 3 4 5 | args = ( 1 , 2 , 3 , 4 ) kw = { 'd' : "baidy" , 'x' : '191991' } f1( * args, * * kw) 结果: a = 1 b = 2 c = 3 args = ( 4 ,) kw = { 'd' : 'baidy' , 'x' : '191991' } |
对于任何函数,都可以通过类似func(*args, **kw)的形式调用它,无论它的参数是如何定义的。
此外,其实并不是必须写成*args
和**kwargs
。 只有变量前面的 *
(星号)才是必须的. 你也可以写成*var
和**vars
. 而写成*args
和**kwargs
只是一个通俗的命名约定。
参数小结:
Python的函数具有非常灵活的参数形态,既可以实现简单的调用,又可以传入非常复杂的参数。
默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误!
要注意定义可变参数和关键字参数的语法:
*args
是可变参数,args接收的是一个tuple;
**kw
是关键字参数,kw接收的是一个dict。
以及调用函数时如何传入可变参数和关键字参数的语法:
可变参数既可以直接传入:func(1, 2, 3)
,又可以先组装list或tuple,再通过*args
传入:func(*(1, 2, 3))
;
关键字参数既可以直接传入:func(a=1, b=2)
,又可以先组装dict,再通过**kw
传入:func(**{'a': 1, 'b': 2})
。
使用*args
和**kw
是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。
命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。
定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符*
,否则定义的将是位置参数