一、为什么要有函数?没有函数带来的困扰?
- 组织结构不清晰,可读性差
- 代码冗余
- 可扩展性差
二、什么是函数?
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户自定义函数。函数需要先定义,后调用。
三、函数的分类
1、内置函数
为了方便我们的开发,针对一些简单的功能,python解释器已经为我们定义好了的函数即内置函数。对于内置函数,我们可以拿来就用而无需事先定义,如len(),sum(),max()
2、自定义函数
很明显内置函数所能提供的功能是有限的,这就需要我们自己根据需求,事先定制好我们自己的函数来实现某种功能,以后,在遇到应用场景时,调用自定义的函数即可。
四、定义函数
1、自定义函数语法:
def 函数名(参数1,参数2,......): “““注释””” 函数体 return 返回值
2、函数的使用原则:先定义,后调用
函数即“变量”,“变量”必须先定义后引用。未定义而直接引用函数,就相当于在引用一个不存在的变量名
#测试一 # 定义阶段 def foo(): print('from foo') bar() # 调用阶段 foo() #报错 #测试二 # 定义阶段 def bar(): print('from bar') def foo(): print('from foo') bar() # 调用阶段 foo() #正常 # 总结:函数的使用必须是先定义,后调用。函数一定要明确区分定义阶段和调用阶段
3、定义函数阶段都发生了什么事?
只检测语法,不执行代码。也就说,语法错误在函数定义阶段就会检测出来,而代码的逻辑错误只有在执行时才会知道。
4、定义函数的三种形式
1、无参函数:应用场景仅仅只是执行一些操作,比如与用户交互,打印
2、有参函数:需要根据外部传进来的参数,才能执行相应的逻辑,比如统计长度,求最大值最小值
3、空函数:设计代码结构
无参函数
# 定义函数 def print_tag(): print('*'*20) def print_msg(): print('hello world') # 调用函数 print_tag() print_msg() print_tag() # 执行结果: ******************** hello world ********************
有参函数
# 定义函数 def my_max(x,y): if x >= y: print(x) else: print(y) # 调用函数 my_max(10,23) # 执行结果 23
空函数
def put(): pass def get(): pass def ls(): pass
总结:
1、定义时无参,意味着调用时也无需传入参数
2、定义时有参,意味着调用时则必须传入参数
五、函数的返回值
1、return:函数内可以有多个return,但是只能执行一次return,执行return函数就立刻结束,并且return后的值,当做本次调用的结果返回。
# 定义函数 def foo(x,y): return x+y # 调用函数 res=foo(1,2) print(res)
1、无return->None
def foo(): pass print(foo()) # 执行结果 None
2、return 1个值->返回1个值
def foo(): pass return 1 print(foo()) # 执行结果 1
3、return 逗号分隔多个值->元组
def foo(): pass return 1,'abc',[1,2,3] print(foo()) #执行结果 (1, 'abc', [1, 2, 3])
4、总结:
a. return返回的值没有类型限制
b. 没有return:默认返回None
c. return一个值,返回值本身
d. return多个值,返回一个元组
六、函数的调用
函数调用的三种形式
# 函数调用的三种形式 def my_max(x,y): if x > y: return x else: return y # 第一种形式:语句形式 res1 = my_max(1,2) print(res1) # 第二种形式:表达式形式 res2=my_max(1,2)*10 print(res2) # 第三种形式:当另外一个函数的参数 res3=my_max(my_max(1,2),3) print(res3) # 执行结果: 2 20 3
七、函数的参数
1、函数的参数分为两种
形参:在定义阶段括号内指定的参数,即变量名
实参:在调用阶段括号内传入的值称之为实参,即变量值
在调用阶段,实参的值会绑定给形参,在调用结束后解除绑定。
def foo(x,y): print(x,y) foo(1,2) # 执行结果: 1 2
2、在python中参数的分类
1、位置参数:按照从左到右的顺序依次定义的参数
位置形参:必须被传值,多一个少一个都不行
位置实参:与形参一一对应传值
2、关键字参数:在函数调用时,按照key=value的形式定义的实参
特点:指名道姓地给形参传值,不再依赖于位置
def foo(name,age,sex): print(name,age,sex) foo('lionel',sex='male',age='18') # 执行结果: lionel 18 male # 注意: # a. 关键字实参必须在位置实参的后面 # b. 不能为同一个参数赋值多次
3、默认参数:在函数定义阶段就已经为形参赋值了
特点:定义阶段已经有值,意味着调用阶段可以不用传值
位置参数通常用于经常变化的参数,而默认参数指的是大多数情况下都一样的
def foo(x,y=1): print(x,y) foo(y=4,x=3) # 执行结果: 3 4 res=1 def foo(x,y=res): print(x,y) res=10 foo(1) # 执行结果: 1 1 # 注意: # a、默认参数必须放到位置形参的后面 # b、默认参数的值只在定义时被赋值一次 # c、默认参数的值通常应该是不可变类型
4、可变长参数:在调用函数时,实参值得个数不固定
实参的形式:位置实参和关键字实参
形参的解决方案:*args,**kwargs
def foo(x,y,*args): #args=(3,4,5,6) print(x,y) print(args) foo(1,2,3,4,5,6) foo(*[1,2,3,4,5,6]) #foo(1,2,3,4,5,6) foo(*(1,2,3,4,5,6)) #foo(1,2,3,4,5,6) # 执行结果: 1 2 (3, 4, 5, 6) 1 2 (3, 4, 5, 6) 1 2 (3, 4, 5, 6)
def foo(x,y,**kwargs): #kwargs={'c':5,'a':3,'b':4} print(x,y) print(kwargs) foo(y=2,x=1,a=3,b=4,c=5) foo(y=2,**{'c':5,'x':1,'b':4,'a':3}) #foo(y=2,x=1,a=3,c=5,b=4) # 执行结果: 1 2 {'a': 3, 'b': 4, 'c': 5} 1 2 {'c': 5, 'b': 4, 'a': 3} def bar(x,y,z): print(x,y,z) def wrapper(*args,**kwargs): bar(*args,**kwargs) wrapper(1,y=2,z=3) # 执行结果: 1 2 3
5、命名关键字参数:指的是定义在*后的参数,该参数必须被传值(除非它有默认值),而且必须按照key=value的形式传值
def foo(x,y,*args,m,n): print(x,y) print(args) print(m,n) foo(1,2,3,n=4,m=3) # 执行结果: 1 2 (3,) 3 4