day10-函数进阶
一、函数的参数
1、位置参数和关键字参数
实参按照传递方式的不同分为位置参数和关键字参数
(1)位置参数
- 调用函数时让形参和实参一一对应(第一个实参给第一个形参赋值,第二个实参给第二个形参赋值)
- 格式:数据1,数据2,数据3,…
(2)关键字参数
- 让实参和形参通过关键字(形参名)对应
- 格式:形参名1 = 数据1(实参),形参名2 = 数据2,…
(3)关键字参数和位置参数混用
- 混用时位置参数必须在关键字参数前面
def func1(x, y, z):
print(f'x:{x}, y:{y}, z:{z}')
# 关键字参数
func1(10, 20, 30) # x:10, y:20, z:30
func1(10, 30, 20) # x:10, y:30, z:20
# 关键字参数(位置不影响调用结果)顺序是没有关系的
func1(x=100, y=200, z=300) # x:100, y:200, z:300
# 混用
func1(10, z=30, y=20) # x:10, y:20, z:30
# func1(x=20, 40, z=40) # 报错:SyntaxError: positional argument follows keyword argument
# 原因:位置参数必须在关键字参数前面
2.参数默认值
定义函数的时候可以以“形参名 = 数据”的形式给参数赋默认值,调用函数的时候有默认值的参数可以不赋值
- 可以给每个形参都赋个默认值
- 当参数有了默认值之后,可以给他附一个新的值也可以不给他赋值
- 如果有的有默认值,有的没有默认值,有默认值的形参必须放在最后,放在没有默认值的参数后面
- 如果想跳过前面的参数,直接给后面的参数赋值,就可以使用默认值参数和关键字参数
def func2(x, y, z):
print(f'x:{x}, y:{y}, z:{z}')
# 参数默认值
def func3(x, y, z=100): # 可以给z赋值,也可以不给他赋值
print(f'x:{x}, y:{y}, z:{z}')
func3(10, 20, 3) # x:10, y:20, z:3
func3(10, 20) # x:10, y:20, z:100
#
# def func4(x, y= 30, z):
# print(f'x:{x}, y:{y}, z:{z}')
# 报错:SyntaxError: non-default argument follows default argument
def func4(x=10, y=100, z=30):
print(f'x:{x}, y:{y}, z:{z}')
# 如果只想让y的值有变化,a和z的值依旧是10和30
func4(y=200) # x:10, y:200, z:30
3.参数类型说明
- 定义函数时可以对参数类型进行说明
- 赋默认值,默认值是什么类型,参数类型说明就是什么类型
- 形参名:数据类型
# 赋默认值
def func5(x=''):
pass
# 形参名:数据类型
def func6(x: list):
x.append()
4.不定长参数 - 主要用于参数个数不确定时
- 在形参前加*或者加**,就可以让这个参数变成不定长参数,不定长参数的形参可以同时接受多个实参
(1)带*的不定长参数
- 带*的参数会变成一个元组,元组中的元素就是对应的实参
- 注意:a.一个函数可以同时存在带*和不带的参数,如果不带的在带星号的后面,不带的参数必须使用关键字参数;b.在调用不定长参数时,即使用带星号的参数时只能用位置参数传参
- 带**的不定长参数后面必须使用关键字参数
(2)带**的不定长参数
- 带**的不定长参数会变成一个字典,调用的时候用关键字参数传参,每个关键字及时字典的key,关键字后面的数据就是字典的value
- 不带双星号的定长参数必须放在带**不定长参数的前面,否则会报错
- 带*的不定长参数和带**的不定长参数可以同时出现,带一个星号的不定长参数必须在前面
- 两个同时出现可以使函数调用时更加灵活
def func7(*x):
print(x)
func7() # ()
func7(10) # (10,)
def func8(x, *y):
print(f'x:{x}, y:{y}')
func8(10) # x:10, y:() 空的元组
func8(10, 20, 30, 40) # x:10, y:(20, 30, 40)
def func9(*x, y):
print(f'x:{x}, y:{y}')
func9(1, 2, 3, y=10)
def func10(**y):
print(y)
# func10(10, 20) # 报错
func10(a=10, c=20, d=23) # {'a': 10, 'c': 20, 'd': 23}
func10() # {}
def func11(x, **y):
print(f'x:{x}, y:{y}')
func11(10, a=20, c=45, d=23) # x:10, y:{'a': 20, 'c': 45, 'd': 23}
func11(x=10, a=20, c=45, d=23) # x:10, y:{'a': 20, 'c': 45, 'd': 23}
def func12(*x, **y):
print(f'x:{x}, y:{y}')
func12(1, 2, 3) # x:(1, 2, 3), y:{}
func12(a=10, b=23) # x:(), y:{'a': 10, 'b': 23}
func12(1, 2, a=2, b=4) # x:(1, 2), y:{'a': 2, 'b': 4}
# 练习:定义一个函数,可以求多个数的和
def sum1(*num):
sum2 = 0
for x in num:
sum2 += x
print(sum2)
sum1(10, 20, 30)
def sum2(*num):
print(sum(num))
sum2(10, 20, 30)
sum2(30, 4, 56, 78) # 168
二、函数返回值
1、什么是返回值
- 返回值就是从函数内部传递到函数外部的数据
- 如果实现函数的功能,产生了一个新的数据一般都需要将这个数据通过返回值返回
2、怎么确定函数返回值
- 在函数体中通过return关键字来返回返回值:return 数据
- 注意:同一个函数中只有一个return有效(因为执行函数体时,只要遇到return,函数直接结束)
- 直接写return相当于return None
- 如果要在一个函数中返回多个数据,用能够保持多个数据的容器,常用元组:return 数据1,数据2,数据3,数据4,…
3、怎么在函数外部获取函数返回值
- 获取函数调用表达式的值就是获取函数返回值
- 返回值对应的数据能做的,函数调用表达式都能做
- 如果函数执行过程中遇到return,return的值是多少,返回值就是多少
- 如果执行过程中没有遇到return,返回None
def sum1(num1, num2):
s = num2 + num1
return s, s/2 # return(s, s/2)
def func1():
return [1, 2, 3]
print(func1()) # [1, 2, 3]
print(func1()[0]) # 1
if func1():
print('您好') # 您好
for x in func1():
print('x:', x)
# x: 1
# x: 2
# x: 3
for x in func1():
print(f'x: {x}')
def func2():
print('abc')
func2() # abc
print(func2()) # None
# 练习: 删除指定列表中所有指定元素
# [1, 23, 4, 5, 1, 34, 2, 1] - 删除元素1
# 产生了一个新的列表,
def deal_number(list1:list, num):
new_list = []
for x in list1:
if x != num:
new_list.append(x)
return new_list
new_list = deal_number([1, 23, 4, 5, 1, 34, 2, 1], 1)
print(new_list)
for x in new_list:
print(f'x: {x}')
三、全局变量和局部变量
根据变量的作用域不同,将变量分为全局变量和局部变量两种
1、全局变量
- 定义在函数和类外面的变量都是全局变量(只要不在函数和类里面,不管在哪里都是全局变量)
- 全局变量的作用域:从定义开始到程序结束的任何地方都可以用
# a是全局变量
a = 10 # 全局变量
# b 和 c 是全局变量
for b in range(4):
c = 10
pass
2、局部变量
- 定义在函数里面的变量是局部变量
- 作用域:从定义开始到函数结束
- 局部变量产生的原因:调用函数的时候,系统会自动为被调用的函数在栈区间开辟一块独立的内存空间,专门用来保存在这个函数中定义的变量,当函数调用结束的时候这块内存空间会自动销毁
# m和x是局部变量
def func3():
x = 'abc'
print(f'函数内部x: {x}')
func3() # 函数内部x: abc
def func4(m=10):
x = abc
print(f'函数内部m:{m}')
3、global 和 nonlocal
- global 和 nonlocal是函数体中的关键字,只能在函数体中使用
(1)global
-
作用:在函数中定义或者修改全局变量
-
用法: global 变量名
-
变量名 = 值
-
使用global在函数中定义全局变量
def func6():
global f
f = 100
func6()
print(f'外部f:{f}') # 外部f:100
- 修改全局变量的值
- 如果直接在函数内部给全局变量赋值,不会修改值,而是产生一个新的局部变量,要想在函数中修改全局变量的值,可以global 变量,在对变量进行赋值
name = '李家半仙儿'
def func7():
name = '熊大' # 此处不是在修改全局变量,而是在定义一个新的局部变量
print(f'函数内部name:{name}') # 函数内部name:熊大
func7()
print(f'函数外部name:{name}') # 函数外部name:李家半仙儿
name = '李家半仙儿'
def func8():
global name
name = '熊大'
print(f'函数内部name:{name}') # 函数内部name:熊大
func8()
print(f'函数外部name:{name}') # 函数外部name:熊大
(2)nonlocal
- 作用:在局部的局部中修改一个局部变量的值
- 用法: nonlocal 变量名
- 变量名 = 值
四、匿名函数
1、什么是匿名函数(lambda)
- 匿名函数的本质还是函数,但是匿名函数只能通过一条语句来实现函数的功能
- 匿名函数是没有函数名的
2、语法
- lambda 形参列表: 返回值
- 函数名 = lambda 形参列表: 返回值
# 求两个数的和
lambda num1, num2: num1+num2
sum1 = lambda num1, num2: num1+num2
# 练习:写一个匿名函数,返回指定的年是否是闰年
lambda year: '闰年' if year % 400 == 0 or (year % 4 == 0 and year % 10 != 0) else '平年'
year = lambda year: print('闰年') if year % 400 == 0 or (year % 4 == 0 and year % 100 != 0) else print('平年')
year(2020)
year = lambda year: year % 400 == 0 or (year % 4 == 0 and year % 100 != 0)
print(year(2020))
year = lambda year: '闰年' if year % 400 == 0 or (year % 4 == 0 and year % 100 != 0) else '平年'
print(year(2020))
五、递归(了解)
1、什么是递归函数
- 在函数中调用函数本身的函数就是递归函数
- 作用:循环能做的,递归都可以做(指导思想:循环能做的就不要用递归,因为用递归太消耗cpu 了)
- 递归控制次数:控制递归函数在指定次数后结束
2、使用递归解决问题的步骤
- 第一步:想定义普通函数一样定义函数
- 第二步:找临界值(找函数结束的条件) - 一般肯函数至少取多少,即最小值
- 第三步:找关系(找f(n)和f(n-1) - 找上次循环和本次循环之间的关系)
- 第四步:假设函数的功能已经实现,通过关系用f(n-1)实现f(n)的功能
def func1(count):
print('=======')
if count == 1:
return
func1(count-1)
print(func1(4))
# count = 5
# def func1():
# global count
# count -= 1
# print('=======')
# if count == 1:
# return
# func1()
#
# 用递归:1+2+3+4+......+100
# f(n) = 1+2+3+4+......+n
# f(n-1) = 1+2+3+4+......+(n-1)
# 关系:f(n)=f(n-1)+n
def sum1(n):
# 1.找临界值
if n == 1:
return 1
# 2.找关系
# sum1(n) = sum(n-1)+n
return sum1(n-1)+n
print(sum1(100))
'''
n=4
*
**
***
****
n=5
*
**
***
****
*****
'''
def print_star(n):
for x in range(1, n+1):
print('*'*x)
print_star(4)
def print_star(n):
# 1.找临界值
if n == 1:
print('*')
return
# 2.关系:先实现f(n-1)然后再打印n个*
print_star(n-1)
print("*"*n)
print_star(4)