一、函数基础
1. 匿名函数
匿名函数就是没有函数名的函数
匿名函数可以看作类型为function的值,与10,'abc'等作用等价
注意
:匿名函数本质还是函数,函数中除了声明语法以外其他的都使用匿名函数
1)语法
lambda 参数列表: 返回值
2)说明
lambda
:关键字
参数列表
:参数名1, 参数名2,...
:
:固定写法(不需要换行和缩进)
返回值
:任何有结果的表达式;它是匿名函数的函数体,相当于普通函数中的return语句
3)参数
普通函数中除了用‘参数名: 类型’的形式来指定参数类型以外,其它的语法匿名函数都支持
fn1 = lambda x, y: x + y
fn2 = lambda x: print(x)
print(fn1(10, 20), fn2(10))
sum1 = lambda x, y, z: x + y + z
print(sum1(1, 2, 3)) # 6
sum1 = lambda x, y, z=30: x + y + z
print(sum1(10, 30)) # 70
sum1 = lambda *num: sum(num)
print(sum1(10, 30)) # 40
2. 变量的作用域
变量在程序中能够使用的范围就是变量的作用域
1)全局变量:没有声明在函数
或者类
里面的变量就是全局变量
作用域是从声明开始到文件结束的任何位置
a = 10 # 全局变量
# x是全局变量
for x in range(5):
b = 10
print('循环里面', a)
print('循环里面', x)
print('外面', b)
def func1():
print('函数里面', a)
print('函数里面', x)
func1()
2)局部变量:声明在函数中的变量就是局部变量
函数的参数相当于声明在函数中的局部变量
作用域是从声明开始到函数结束的任何位置
def func2(x1=10, y1=20):
z1 = 100
print('函数内部:x1:{}, y1:{}, z1:{}'.format(x1, y1, z1))
func2()
print('函数外:', x1) # NameError: name 'x1' is not defined
print('函数外:', z1) # NameError: name 'z1' is not defined
3)函数调用过程(内存):压栈
当调用函数的时候,系统会自动在内存的栈区间为这个函数开辟一个独立的内存区域
用来保存在函数中声明的变量,当函数调用结束内存区域会自动释放
3. global和nonlocal
global和nonlocal都是在函数中的关键字,和return相同只能在函数体中使用
1)global:在函数中声明一个全局变量
global 变量
变量 = 值
a = 111 # 全局变量a
def func3():
a = 222 # 局部变量a
print('in:', a)
global b # 全局变量b
b = 333
print('in:', b)
func3()
# in: 222
# in: 333
# out 111
# out 333
print('out', a)
print('out', b)
2)nonlocal:在局部的局部中去修改局部变量的值
nonlocal 变量
变量 = 值
def func4():
a2 = 100
def func5():
nonlocal a2
a2 = 500
print('in function5:a2', a2)
func5()
print('in function4:a2', a2)
# in function5:a2 500
# in function4:a2 500
func4()
二、函数递归
1. 什么是递归函数
自己调自己的函数(函数体中调用当前函数)
循环能做的事情,递归都可以做
注意
:能用循环解决的问题就不要用递归
2. 怎么写递归函数
第一步:找临界值(循环结束的条件) - 在这里需要结束函数
第二步:找关系 - 找f(n)和f(n - 1)的关系(找档次循环和上次循环的关系)
第三步:假设函数的功能已经实现,根据关系用f(n - 1)去实现f(n)的功能
# 递归函数1 + 2 + 3 + ... + n
def sum1(n):
if n == 1:
return 1
return n + sum1(n - 1)
print(sum1(100)) # 5050
# 递归函数实现:1,1,2,3,5,8,13,21,34....
def sequence(n):
if n == 1 or n == 2:
return 1
return sequence(n - 2) + sequence(n - 1)
print(sequence(10)) # 55
# 练习:用递归实现以下功能
"""
n = 5
*****
****
***
**
*
"""
def print_star(n: int):
if n == 1:
print('*')
return
print('*' * n)
print_star(n - 1)
三、迭代器和生成器
1. 迭代器
迭代器作为容器可以保存多个数据
数据的来源:将其他序列转换成迭代器;生成器
1)将其他序列转换成迭代器
iter1 = iter('abc')
# <str_iterator object at 0x10e328438> <class 'str_iterator'>
print(iter1, type(iter1))
iter2 = iter([12, 30, 90])
# <list_iterator object at 0x10e328550> <class 'list_iterator'>
print(iter2, type(iter2))
2. 获取元素
不管用哪种方式去获取了元素的值,这个元素在迭代器中就不再存在了
1)获取单个元素:
next(迭代器)、迭代器.next() ---> 获取迭代器中的第一个元素
iter3 = iter('hello')
print(next(iter3)) # h
print(next(iter3)) # e
print(next(iter3)) # l
print(iter3.__next__()) # l
print(iter3.__next__()) # 0
# 如果迭代器为空,再次获取元素时会报错
# print(iter3.__next__()) # StopIteration
2)遍历
for 变量 in 迭代器:
pass
iter4 = iter('world')
for item in iter4:
print(item)
# w
# o
# r
# l
# d
# print(next(iter4)) # StopIteration
iter4 = iter('world')
print(next(iter4))
for item in iter4:
print('循环:', item)
# w
# 循环: o
# 循环: r
# 循环: l
# 循环: d
2. 生成器
1)什么是生成器
生成器就是迭代器中的一种
调用一个带有yield关键字的函数就可以得到一个生成器
如果一个函数中有yield关键字:
a. 调用函数不会执行函数体
b. 函数调用表达式的值不是函数的返回值,而是一个生成器对象
2)生成器产生数据的原理
a. 一个生成器能够产生多少数据
是由执行完生成器对应的函数函数体遇到yield的次数决定的
yield后面的值就是生成器能够产生的数据
b. 每次获取生成器元素时
都是先去执行函数体直到遇到yield,并且将yield后面的值作为获取元素的结果;
并且保留结束的位置,下次获取值时,会从上超车结束的位置继续执行函数体,直到遇到yield...
如果从开始执行到函数结束都没有遇到yield,就会报StopIteration错误
def func4():
for x in range(0, 100, 3):
yield x
gen4 = func4()
print(next(gen4)) # 0
print(next(gen4)) # 3
print(next(gen4)) # 6