想象生活中的例子,修理工需要实现准备好工具箱里面放好锤子,扳手,钳子等工具,然后遇到锤钉子的场景,拿来锤子用就可以,而无需临时再制造一把锤子。
修理工=>程序员
具备某一功能的工具=>函数
要想使用工具,需要事先准备好,然后拿来就用且可以重复使用
要想用函数,需要先定义,再使用
ps:函数就是盛放代码的容器
为了解决下述问题:
1)代码的组织结构不清晰,可读性差
2)遇到重复的功能只能重复编写实现代码,代码冗余
3)功能需要扩展时,需要找出所有实现该功能的地方修改之,无法统一管理且维护难度极大
3.1、定义的语法
#语法
def 函数名(参数1,参数2,参数3,...):
‘‘‘注释‘‘‘
函数体
return 返回的值
调用的语法
#函数名要能反映其意义
3.2、定义函数
发生的事情
1)申请内存空间把函数体代码放进去
2)将函数内存地址绑定给函数名
强调:定义函数只检测语法,不执行代码。也就说,语法错误在函数定义阶段就会检测出来,而代码的逻辑错误只有在执行时才会知道
3.3、函数的调用
发生的事情:
1)先通过函数名定位到函数的内存地址
2)函数内存地址()->触发函数体代码的运行
强调:调用函数才会执行函数体代码
例1:
def func():
print(11111 #False 语法错误
例2:
def func():
print(1111)
x
print(2222)
func() # False 逻辑错误
例3
def bar():
print(‘from bar‘)
def foo():
print(‘from foo‘)
bar()
foo()
=================
def foo():
print(‘from foo‘)
bar()
def bar():
print(‘from bar‘)
foo() #Fales 反了,要先定义,再调用
3.4、定义函数的三种形式
ef say():
print(‘========‘)
print(‘welcome to here‘)
print(‘========‘)
say()
def login():
inp_name = input("username>>>: ").strip()
inp_pwd = input("password>>>: ").strip()
if inp_name == "egon" and inp_pwd == "123":
print(‘login successful‘)
else:
print("username or password error")
login()
def max2(x,y)
if x > y:
print(x)
else:
print(y)
max2(10,20)
def login():
pass
定义时无参,意味着调用时也无需传入参数
定义时有参,意味着调用时则必须传入参数
3.5、调用函数的三种形式
1)语句形式
len(‘hello‘) / foo( )
res=len(‘hello‘)*10
print(res)
print(len("hello"))
总体分为两大类:
形参:在函数定义阶段括号内指定的参数,称之为形式参数,简称形参-》变量名
实参:在函数调用阶段括号内传入的值,称之为实际参数,简称实参-》变量的值
形参与实参的关系是:在调用函数时,实参值会绑定给形参名,在函数调用完毕后解除绑定
1、位置形参:在定义函数时,按照从左到右的顺序依次定义的变量名,称之为位置形参
? 特点:每次调用,必须被赋值
ef func(name,age):
print(name)
print(age)
func(1,2)
2、默认形参:在定义函数时,就已经为某个形参赋值了,称之为默认形参
? 特点:调用函数时,可以不用为其赋值
def func(name,age=18):
print(name)
print(age)
func("egon")
func("egon",19) # 19 以调用的为准
& 注意 : 可以混用位置形参与默认形参,但是
? 1)、位置形参必须在前面
? 2)、默认形参的值通常应该是不可变类型
? 3)、默认形参的值是在函数定义阶段赋值的
ef func(name,hobby,hobbies = None):
if hobbies is None:
hobbies = []
hobbies.append(hobby)
print(‘%s的爱好是%s‘ %(name,hobbies))
func(‘egon‘,‘read‘)
func(‘tom‘,‘play‘)
func(‘jack‘,‘music‘)
func(‘lili‘,‘eat‘,["movie"])
m=1111
def func(x,y,z=m):
print(x)
print(y)
print(z)
m=666
func(1,2) # m仍然是1111,以先定义的为准
1、位置实参:在调用函数时,按照从左到右的顺序依次传入的值,称之为位置实参
? 特点:按照位置为形参赋值,一 一对应
def res(name,age)
...
res(‘egon‘,18)
2、关键字实参:在调用函数时,按照key=value的形式传值,称之为关键字实参
? 特点:可以打乱顺序,但是仍然能够指定道姓地为指定的形参赋值
def res(name,age)
...
res(age=18,name="egon")
& 注意:可以混用位置实参与关键字实参,但是
? 1)、位置实参必须在关键字实参的前面
? 2)、不能为同一形参重复赋值
def res(name,age)
...
func("egon",age=18) # True
func(age=18,"egon") # 语法错误
def foo(x,y,z):
pass
foo(1,y=2,3) # 错误
foo(1,y=2,z=3,x=4) # 错误,不能重复调用
可变长参数指的是在调用函数时,传入的实参个数不固定,对应着必须有特殊形式的形参来接收溢出的实参
实参无非两种形式======>
? 溢出的位置实参--->*
? 溢出的位置关键字实参--->**
一.. ==============*与**在形参中是一种汇总行为=====================
1、*在形参中的应用: *会将溢出的位置实参合并成一个元组,然后赋值给紧跟其后的那个形参
def func(x,*args): # y = (2,3,4,5)
print(x)
print(args)
func(1,2,3,4,5)
def my_sum(*args):
res = 0
for i in args:
res += i
print(res)
my_sum(1,2) 结果为 1+2=3
2、2个* . 在形参中的应用:* *会将溢出的关键字实参合并成一个字典,然后赋值给紧跟其后的那个形参名
def func(x,**kwargs): # kwargs = {"a":2,"c":4,"b":3}
print(x)
print(kwargs)
func(1,a=2,b=3,c=4)
二 ..==============*与**在实参中是一种打散行为=====================
1、*在实参中的应用:*后可以跟可以被for循环遍历的任意类型,*会将紧跟其后的那个值打散成位置实参
def func(x,y,z):
print(x)
print(y)
print(z)
func(*[11,22,33]) # 11,22,33
func(*"hel") # h,e,l
unc(*{"x":111,"y":2222,"z":3333}) # x,y,z
2、**在实参中的应用:**只能跟字典类型,**会将字典打散成关键字实参
def func(x,y,z):
print(x)
print(y)
print(z)
func(**{"x":111,"y":2222,"z":3333})
def index(x,y,z):
print(x,y,z)
def wrapper(*args,**kwargs): # args=(1,2,3,4,5,6) kwargs={"a":1,"b":2,"c":3}# index(*args,**kwargs) # index(*(1,2,3,4,5,6),**{"a":1,"b":2,"c":3})# # index(1,2,3,4,5,6,a=1,b=2,c=3)#
wrapper(1,2,3,4,5,6,a=1,b=2,c=3)
wrapper(1,y=2,z=3)
了解(**):命名关键字形参: 在*与**中间的形参称之为命名关键字形参
特点: 必须按照key=value的形式传值
def func(x,m=333,*args,y=222,z,**kwargs):
print(x)
print(args)
print(y)
print(z)
print(kwargs)
func(1,2,3,z=4,a=1,b=2,c=3)
原文:https://www.cnblogs.com/caodan01/p/14201917.html