5.5 函数的参数定义
1️⃣ 函数定义默认值参数,函数在定义的时候,我们可以给形式参数设置默认值,只有当默认值不符的时候才需要传递实参:
# 博主:辰chen # 博客地址:https://chen-ac.blog.csdn.net/ # 开发时间:2021/12/19 10:22 # 欢迎大家关注AIoT相关博客~ def fun(a, b = 10): # 给b设置默认值为10 print('a =', a) print('b =', b) fun(1) # 只传入一个参数,只给a赋值 fun(1, 10) # 传入两个参数,但是传给b的参数等于b的默认参数 fun(1, 2) # 传入两个参数,传给b的参数不等于b的默认参数
我们知道,类似 print() 这类函数是系统为我们准备好的,不妨想一下,pint() 是默认输出后换行的,我们可以修改 end 使 print() 不是默认换行,这是否意味着系统的 print() 函数具体实现中是给 end 默认赋值为 \n 呢?
我们可以在 PyCharm 中打出一个 print(),然后按下键盘中的 Ctrl 键同时鼠标指向 print(),点击 print() 就可以查看 print() 实现代码:
从这里我们确确实实可以看出,系统实现 print() 函数的时候,设置默认参数 end='\n',故当我们不传入 end 的时候,默认输出换行,我们当然也可以自行设置 end 的值,达到我们想要的输出结构
2️⃣ 个数可变的位置参数,我们在写函数的时候,我们可能有时候不能确定我们到底有几个位置参数,这个时候,我们就可以采取*参数名的方式,最终返回的是一个元组:
# 博主:辰chen # 博客地址:https://chen-ac.blog.csdn.net/ # 开发时间:2021/12/19 10:22 # 欢迎大家关注AIoT相关博客~ def printf(*a): print(a) printf(10) printf(10, 20) printf(10, 20, 30, 40)
3️⃣ 个数可变的关键字形参,和位置参数一样,我们同样可以按照类似的方式去定义个数可变的关键字形参,语法格式为**参数名,最终的返回值是一个字典
# 博主:辰chen # 博客地址:https://chen-ac.blog.csdn.net/ # 开发时间:2021/12/19 10:22 # 欢迎大家关注AIoT相关博客~ def printf(**a): print(a) printf(a = 10) printf(a = 10, b = 20) printf(a = 10, b = 20, c = 30, d = 40)
4️⃣ 同时有个数可变的关键字形参和个数可变的位置形参,要求个数可变的位置形参放在个数可变的关键字形参之前,否则报错
def act(*a, **b): pass
5.6 变量的作用域
🚩变量的作用域其实就是指程序代码能访问该变量的区域,我们根据变量的有效范围可以把变量划分为:
1️⃣ 局部变量:在函数内定义使用的变量,只在函数内有效,局部变量可以使用 global 声明,声明后的变量就会变成全局变量
2️⃣ 全局变量:函数体外定义的变量,可用于函数内外
# 博主:辰chen # 博客地址:https://chen-ac.blog.csdn.net/ # 开发时间:2021/12/19 16:53 # 欢迎大家关注AIoT相关博客~ def add(a,b): c = a + b # c 就称为局部变量,因为c在是函数体内进行定义的变量 # a, b为函数的形参,作用范围也是函数内部,相当于局部变量 print(c) #print(c) 报错,因为 a, c超出了起作用的范围(超出了作用域) #print(a) name='辰chen' #name的作用范围为函数内部和外部都可以使用 -->称为全局变量 print(name) def func1(): print(name) #调用函数 func1() def func2(): global age #函数内部定义的变量称为局部变量 # 局部变量使用global声明,这个变量实际上就变成了全局变量 age=19 print(age) func2() print(age)
5.7 递归函数
🚩递归函数其实就是指在函数内部自己调用自己的这么一类函数,当然,自己调用自己也是有一个度的,否则就会:爱的魔力转圈圈,出不来可不行,所以,递归函数最重要的一部分就是递归终止的条件,比如我们要计算 n 的阶乘,我们知道 n 的阶乘等于 n * n-1 的阶乘,上述思想其实就是递归的思想,退出递归的条件则是当 n = 1 的时候,返回 1
# 博主:辰chen # 博客地址:https://chen-ac.blog.csdn.net/ # 开发时间:2021/12/19 17:18 # 欢迎大家关注AIoT相关博客~ def fac(n): if n == 1: # 当n=1,退出递归 return 1 else: return n * fac(n - 1) # n的阶乘等于n * n-1的阶乘 print(fac(6))
递归的调用过程 :
每递归调用一次函数,都会在栈内存分配一个栈帧,每执行完一次函数,都会释放相应的空间(这一点不需要理解,学完数据结构后,会自然理解这句话的含义)
递归的优缺点:
缺点:占用内存多,效率低下,
优点:思路和代码简单
5.8 lambda 表达式
🚩lambda 表达式用来声明匿名函数,即一些我们没有命名的,临时需要调用的小函数,lambda 表达式常用在我们临时需要一个类似函数的功能但又不想定义函数的场合,当然,我们也可以使用 lambda 表达式定义具名函数。
lambda 表达式只可以包含一个表达式,不允许包含复杂语句和结构,但是我们可以在表达式中调用其他的函数,lambda 表达式的计算结果相当于函数的返回值.
# 博主:辰chen # 博客地址:https://chen-ac.blog.csdn.net/ # 开发时间:2021/12/17 18:56 # 欢迎大家关注AIoT相关博客~ # 我们可以给我们的 lambda 表达式起一个名字 add = lambda x, y, z: x + y + z print(add(1, 2, 3)) # lambda 表达式支持默认参数 add = lambda x, y = 2, z = 3: x + y + z print(add(1)) # lambda 表达式可作为函数参数 l = [item for item in range(5)] print(l) print(list(map(lambda x: x + 5, l)))
*5.9 生成器函数
注:本小节带 *,不需要进行学习,可以简单进行了解
⛲️ 包涵 yield 语句的函数可用来创建生成器对象,我们称这样的函数为生成器函数,yield 语句与 return 语句作用类似,都用来返回函数的值。与 return 语句不同的是,return 语句一旦执行就会立刻结束函数的运行,而每次执行到 yield 语句并返回一个数之后会暂停或挂起后面代码的执行,下次通过生成器对象的 __next__() 方法、内置函数 next()、for 循环遍历生成器对象元素或其他方式显示“索要”数据时恢复执行。生成器具有惰性求值的特点,适合大数据处理。
例:编写并使用能够生成斐波那契数列的生成器函数
# 博主:辰chen # 博客地址:https://chen-ac.blog.csdn.net/ # 开发时间:2021/12/17 15:27 # 欢迎大家关注AIoT相关博客~ def f(): a, b = 1, 1 while True: yield a a, b = b, a + b a = f() # 创建生成器对象 for i in range(10): # 斐波那契数列中前10个元素 print(a.__next__(), end = ' ') print() for i in f(): # 斐波那契数列中第一个大于100的元素 if i > 100: print(i, end = ' ') break