Python学习之—自定义函数(def())的使用+相关操作
知识索引
首先牢记:
关键字参数不可以在位置参数和普通参数的前面
可变关键字参数,不可以在可变位置参数和普通参数前面.
重要的事说三遍!!!牢记~~~
这是后面判断定义的函数和函数调用是否正确的重要方法,往往会忘记.
函数:
数学定义
y=f(x),y是x的函数,x是自变量.
Python函数
● 由若干语句组成的语句块,函数名称,参数列表,它是组织代码的最小单元
● 完成一定功能
函数作用:
● 结构化编程对代码的最基本的封装,一般按照功能组织一段代码
● 封装目的是为了复用,减少冗余代码
● 代码更加美观,可读易懂!
分类:
● 内荐函数 如max() reverse()
● 库函数 如math() ceil()
● 自定义函数 使用def()关键字定义
函数定义
def function name (parameter):
function body
return
● 函数名就是标识符,命名要求与变量命名要求一样
● 语句块必须缩进,预定4个空格
● Python的函数若没有return语句,会隐式返回一个None值
● 定义中的参数列表称为形式参数,只是一种符号标识符
函数调用
● 函数定义,只是声明了一个函数,它不能被执行,需要调用执行
● 调用的方式,就是函数名后加上小括号,如有必要在括号内填写上参数
● 调用时写的参数是实际参数,是实实在在传入的值,简称实参
def add(x,y): #x y 为形式参数,也是标识符.add指向函数对象
return x +y # 需要返回值就用return
add(4,5) #函数的调用,函数名后使用小括号,小括号内填入实际实实在在的参数,简称实参.
add(4,5),add('a','b'),add([0],[2])
>>> (9, 'ab', [0, 2])
函数本身是一个callable()[可调用对象]
callable(add) #返回是否是可调用.True False
函数参数
函数在定义时要约定好形式参数,调用时也提供足够的实际参数,一般来说,形参和实参个数需要一致.(可变参数除外)
传参方式
(1) 位置传参
定义def fun(x,y,z),调用 fun(1,2,3),按照参数定义顺序传入实参.
(2) 关键字传参
定义时def fun(x, y, z),调用使用 fun(x=1, y=3, z=5),使用形参的名字来传入实参的方式,如果使用了形参名字,那么传参顺序就可和定义顺序不同
要求位置参数必须在关键字参数之前传入,位置参数是按位置对应的
def fun(x, y, z):
pass
fun(1,2,3)
fun(x=10,z=15,y=20)# 关键字传参不考虑传参的顺序,但个数要一致.可以用位置和关键字一同传参.
fun(12,y=20,z=10)# 关键与位置传参组合使用
def add(x=20,y):# 错误 关键字缺省值不能写前
return x+y
add(y=10,10) #错误关键字传参不能写前面
函数缺省值
★缺省值也称为默认值,可以在函数定义时,为形参增加一个缺省值。
其作用:
● 参数的默认值可以在未传入足够的实参的时候,对没有给定的参数赋值为默认值
● 参数非常多的时候,并不需要用户每次都输入所有的参数,简化函数调用
def add(x=4, y=5):
return x+y
测试调用
add()、add(x=5)、add(y=7)、add(6, 10)、add(6, y=7)、add(x=5, y=6)、add(y=5, x=6)、
add(x=5, 6)、add(y=8, 4)、add(11, x=20)#报错么????
其中:
add(x=5, 6)、add(y=8, 4)、add(11, x=20)
这三个调用时会报错,原因是什么呢?
首先,关键字传参不允许在位置传参之前,这个前面有写,再者,同一个参数只能传参一次,在add(11,x=20)中,函数默认的将11传给了x,后面又传一个x=20,这两个相违背,所以会报错.
能否这样定义 def add(x, y=5) 或 def add(x=4,y)— ?
参数缺省值举例:
#定义一个函数login,参数名称为host、port、username、password
def login(host='127.0.0.1', port='8080', username='wayne', password='magedu'):
print('{}:{}@{}/{}'.format(host, port, username, password))
login()
login('127.0.0.1', 80, 'tom', 'tom')
login('127.0.0.1', username='root')
login('localhost', port=80, password='com')
login(port=80, password='magedu', host='www')
可变参数
可变位置参数
在形参前使用 * 表示该形参是可变位置参数,可以接受多个实参 他将收集来的实参组织到一个tuple中.
示例:
def sum(iterable):
result =0
for x in iterable:
result += x
return result
sum([1,2,3])# 这种参数传参需要用一个可迭代对象传参,只是一个参数
def sum(*iterable):#可变的位置参数,将收集的数据放置在元组中
result=0
# print(type(iterable),iterable)
for x in iterable:
result += x
return result
sum(1,2,3)
>>> 8 #直接传入多个参数,先封装成一个元组,这里是多个参数.注意二者的不同用法
可变关键字参数
在形参前使用 ** 表示该形参是可变关键字传参,可以接受多个关键字传参.
def showconfig(**kwargs):
print(type(kwargs))
print(kwargs)
showconfig(a=1,b=2)
>>>
<class 'dict'>
{'a': 1, 'b': 2}
可变位置参数与可变关键字参数的混合使用
可以定义为下列方式吗?
def showconfig(username, password, **kwargs)
def showconfig(username, *args, **kwargs)
def showconfig(username, password, **kwargs, *args) # ?# 不可以!!!!
总结:
● 有可变位置参数和可变关键字参数
● 可变位置参数在形参前使用一个星号*
● 可变关键字参数在形参前使用两个星号**
● 可变位置参数和可变关键字参数都可以收集若干个实参,可变位置参数收集形成一个tuple,可变关键字参数收集形成一个dict
● 混合使用参数的时候,普通参数需要放到参数列表前面,可变参数要放到参数列表的后面,可变位置参数需要在可变关键字参数之前
举例;
def fn(x, y, *args, **kwargs):
print(x, y, args, kwargs, sep='\n', end='\n\n')
fn(3, 5, 7, 9, 10, a=1, b='abc')# x=3,y=5,(7,9,10 )作为一个元组,剩下的作为字典
fn(3, 5)# 可以,可变参数可以是0个或多个
fn(3, 5, 7)#可以
fn(3, 5, a=1, b='abc')#可以,可变位置参数为0
fn(x=3, y=8, 7, 9, a=1, b='abc') # ? 不可以,关键字参数在普通参数前面
fn(7, 9, y=5, x=3, a=1, b='abc') # ?同样不可以,定义重复
keyword-only 参数
在Python3之后,新增了keyword-only参数。
keyword-only参数:在形参定义时,在一个*星号之后,或一个可变位置参数之后,出现的普通参数,就已经不是普通的参数了,称为keyword-only参数。
举例:
def fn2(*args,x):
print(x)
print(args)
fn2(1,2,3,4)#报错,因为可变位置参数尽可能多的收集所有的位置参数.后面的x得不到数据,所以只能用keyword-only进行传参.
错误定义举例:
def fn2(a,b,*args=(10,20),**kwargs):# 报错,可变位置参数,本身就可以收集0个元素,不需要缺省值,因此会语法报错.
pass
def fn(**kwargs ,a,b,x=5) #关键字参数在后
keyword-only参数另一种形式
def fn(a,b,*,z,**kwargs): # * 号后所以的普通参数都成了keyword-only的参数了.
pass
fn(1,2,z=6)
参数混合使用练习:
# 可变位置参数、keyword-only参数、缺省值
def fn(*args, x=5):
print(x)
print(args)
fn() # 等价于fn(x=5)
fn(5)
fn(x=6)
fn(1,2,3,x=10)
# 普通参数、可变位置参数、keyword-only参数、缺省值
def fn(y, *args, x=5):
print('x={}, y={}'.format(x, y))
print(args)
fn() # 报错, y 取不到值,报错
fn(5)# y=5,*args 为空元组,x=5 缺省值
fn(5, 6) #y =5,6给元组,x=5缺省值
fn(x=6) # 报错,y无参数
fn(1, 2, 3, x=10)# 1给y,2,3给元组,x=10,缺省值
fn(y=17, 2, 3, x=10) # 报错,关键字传参在其他之前,返回顶端,牢记!!!
fn(1, 2, y=3, x=10) #报错,y重复定义.
参数规则
参数列表参数一般顺序是:普通参数、缺省参数、可变位置参数、keyword-only参数(可带缺省值)、可变关键字参数。
注意:
● 代码应该易读易懂,而不是为难别人
● 请按照书写习惯定义函数参数
● 定义最常用参数为普通参数,可不提供缺省值,必须由用户提供。注意这些参数的顺序,最常用的先定义
● 将必须使用名称的才能使用的参数,定义为keyword-only参数,要求必须使用关键字传参
● 如果函数有很多参数,无法逐一定义,可使用可变参数。如果需要知道这些参数的意义,则使用可变关键字参数收集
参数解构
参数解构原则:
在给函数提供实参的时候,可以在可迭代对象前使用 * 或者 ** 来进行结构的解构,提取出其中所有元素作为函数的实参
● 使用 * 解构成位置传参
● 使用 ** 解构成关键字传参
● 提取出来的元素数目要和参数的要求匹配
举例:
def add(x,y):
return x+y
add(*[4,5]),add(*{4,5}),add(*(4,5)),add(*range(4,6))
*{'a':1,'b':2}.items() #参数解构只能写在传实参的地方才可以使用
add(*{'a':2,'b':3)
>>>ab #默认的会按照字典的key进行解构,数字的相加,字符串按照字符串相加.
add(**{'a':1,'b':2}) #解构成a=1,b=2 ,将字典结构成关键字传参,除了字典以外,不能使用两个星号进行传参.
add(**{'x':1,'y':2})或者add(*{'a':1,'b':2}.values()) #用**解构,按关键字传参需要传入的参数一样.