匿名函数、内置函数、迭代器、异常捕获、生成器
匿名函数
什么是匿名函数?
- 没有名字的函数
语法格式
- lambda 形参:返回值
匿名函数一般不会单独使用,往往都是配合其他函数一起使用
res = lambda x: x ** 2
print(res(2))
内置函数
# 1.map() 映射
格式 格式:map(function,iterable) # iterable:可迭代对象
第一个参数为函数名,第二个参数为可迭代对象
过程 循环遍历可迭代对象中的每一个元素传递给function函数,保存返回值,返回一个新的可迭代对象,并没有修改原理的可迭代对象。
l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# def index(n):
# return n ** 2
print(list(map(lambda x: x ** 2, l)))
# 2.zip() 拉链
格式 filter(function , iterable)
function为函数名,iterable为可迭代对象
l = [11, 22, 33]
name_list = ['jason', 'kevin', 'tony', 'jerry']
# 将两个列表内的元素通过小元组的形式一一对应,放置在一个新的列表中
new_list = []
for i in range(len(l)):
new_list.append((l[i],name_list[i]))
print(new_list)
res = list(zip(l, name_list))
print(res)
# 3.max与min max求最大值 min求最小值
格式 max(*args, key=None)
min(*args, key=None)
参数key用来指定一个函数,此函数的功能就是制定排序的规则,一般用lambda函数
d = {
'jason':3000,
'Bevin':1000000,
'Ascar':10000000000,
'aerry':88888
}
# 比较值,返回key
def index(key):
return d[key]
print(max(d,key=lambda key:d[key])) # Ascar
print(min(d,key=lambda key:d[key])) # jason
# 4.filter 过滤
格式: filter(function , iterable)
function为函数名,iterable为可迭代对象
l = [11, 22, 33, 44, 55]
res = filter(lambda x:x>30,l)
# 5.reduce 归总
ps:在python 3.0.0.0以后, reduce已经不在built-in function里了, 需要from functools import reduce.
格式 reduce(function,sequence [ ,initial] )
function为函数名,function中必须是两个参数,sequence为序列,initial有指定的值相当于追加使用数据,或当sequence为空,作为返回值。
列表求和
from functools import reduce
d = [11, 22, 33, 44, 55, 66, 77, 88, 99]
res = reduce(lambda x, y: x + y, d)
实现6的阶乘
from functools import reduce
res = reduce(lambda x, y: x * y,[x for x in range(1,7)])
内置函数一览表
功能 | 描述 | 例子 |
---|---|---|
abs() | 求绝对值 | abs(123)/abs(-123) |
all() | 判断给定的可迭代参数iterable中的所有元素是否都为TRUE | 空元组、空列表 返回值为True |
any() | 判断给定参数,其中一个参数为True,则为True | l = [1,2,0] print(any(l))>>True |
bin() | 二进制转换 | bin(10) |
oct() | 八进制转换 | oct(10) |
hex() | 十六进制转换 | hex(10) |
bytes() | 编码转换 | res = '艾伦' print(bytes(res,'utf8')) |
str() | 字符串转换 | str(1) |
encode() | 编码 | '艾伦'.encode('utf8') |
decode() | 解码 | b'\xe8\x89\xbe\xe4\xbc\xa6'.decode('utf8') |
callable() | 是否可调用 | def index(): pass print(callable(index))>>True |
chr() | 根据数字匹配ASCII码 | chr(65)>>>A |
ord() | 根据ASCII码匹配数字 | ord('A')>>>65 |
complex | 复数 | complex(1+2j) |
dir() | 查看当前对象可调用的名字 | dir(调用对象) |
divmod() | 分页 | 利用余数判断是否需要另外分页divmod(102,10) |
eval() | 只识别字符串中简单的语法 | 识别简单的语法并执行 |
exec() | 识别字符串中复杂点的语法 | 识别复杂的语法并执行 |
isinstance() | 判断对象是否属于某个数据类型 | isinstance(123,int) >>>True |
pow() | 幂运算 | pow(2,3)>>>8 |
round() | 四舍五入 | round(8.5)>>>8 |
迭代器
- 迭代,即为更新换代,每次更新都必须依赖上一次的迭代结果
ps:迭代给我们提供了一种不依赖索引取值的方式
- 可迭代对象
通俗的讲,内置方法中有__iter__方法的都可以称之为可迭代对象
含括了字符串、列表、元组、字典、集合、文件对象__iter__方法在调用的时候还有一个简便的写法iter()
一般情况下所有的双下方法都会有一个与之对应的简化版本 方法名()
d = {'username':'alan','pwd':123}
print(d.__iter__()) # 获取得是字典的key
- 迭代器对象
简单的说,即含有__iter__方法 又含有__next__方法
其中文件对象是不需要转换,本身就就是迭代器对象
其他类型的可迭代对象,需要__iter__转化一下
为啥子一定要整出一个迭代器对象呢?
其中一个最最最主要的因素是寻找出一个不依靠索引就能实现取值的功能
d = {'username':'alan','pwd':123}
res = iter(d)
print(next(res)) # username
print(next(res)) # pwd
print(next(res)) # 当元素取完后,再取值就会报错
for循环本质
l1 = [1,2,3,4,5,6,7,8,9,11,22,33,44,55]
# 要求,循环打印l1内每一个元素,但不能使用for循环 __next__() next()
res = l1.__iter__()
while True:
print(res.__next__()) # 很明显,在这一步一直循环,等所有元素取完后,再取直接报错,所以在这一步加入了异常捕获操作
方法一:
n = 0
while n < len(l1):
print(res.__next__())
n += 1
方法二:
d = {'name':'alan','pwd':123,'hobby':'read'}
res = d.__iter__()
while True:
try:
print(res.__next__())
except StopIteration as e:
break
异常捕获
- 什么是异常捕获
代码运行出错会导致异常 异常出现后如果没有对应的解决方案,则整个程序会直接结束
- 异常的三个重要组成部分
1.traceback
错误位置,翻到提示信息最下面,点击一下链接,直接挑战出错对应位置
2.XXXError
错误类型
3.错误类型后面的类型
这个是报错的详细原因(很重要,很多问题都能依此找到解决问题的方法)
- 错误的种类
语法错误
这种情况是不被允许的,一旦出现立刻改正
逻辑错误
可以被允许,但是要尽量避免
- 异常捕获基本语法
try:
有可能会出错的代码
except 错误类型 as e:
出错之后对应的处理机制(e是指错误的详细信息)
except 错误类型 as e1:
出错之后对应的处理机制(e是指错误的详细信息)
except 错误类型 as e2:
出错之后对应的处理机制(e是指错误的详细信息)
万能异常处理Exception
try:
# int('abc')
print(name)
# l = [11]
# l[100]
except Exception:
print('你来啥都行 无所谓')
异常捕获句式和万能异常
1.有可能会出现错误的代码才需要被监测
2.被监测的代码一定要越少越好
3.异常捕获使用频率越低越好
- 异常捕获完整版
try:
被检测的代码
except 错误类型 as e:
...
else:
被检测的代码不报错的时候执行的命令
finally:
无论是否报错,都会执行
# 断言assert
name = 'alan'
assert isinstance(name,str)
# 主动报错
raise 错误类型
迭代器取值与索引取值小结
迭代取值
优点:
1.不依赖于索引的一种通用取值方式
缺点:
1.取值的顺序永远都是固定的从左往右 无法重复获取
索引取值
缺点:
1.需要提供有序容器类型才可取值(不是一种通用的方式)
优点:
1.可以重复取值
生成器
- 什么是生成器
生成器本质就是自定义的迭代器,具名关键字yield
# 定义阶段就是一个普通函数
def my_ge():
print('first')
yield 123, 152
print('second')
yield 'alan'
res = my_ge() # 第一次调用函数,将函数转变成生成器
ret = res.__next__() # first 每执行一个next,代码运行到yield停止并返回后面的参数
print(ret) # (123, 152)
ret = res.__next__() # second
print(ret) # alan
- range函数的本质
def my_range(start, stop=None, step=1):
if not stop:
stop = start
start = 0
while start < stop:
yield start
start += step
for i in my_range(5):
print(i)
- yield传值
def eat(name):
print('%s准备干饭!!!' %name)
while True:
food = yield
print('%s正在吃%s'% (name,food))
res = eat('alan')
res.__next__()
res.send('盖浇饭')
- yield与return对比
yield
1.可以返回值(支持多个并且组织成元组)
2.函数体代码遇到yield不会结束而是"停住"
3.yield可以将函数变成生成器 并且还支持外界传值
return
1.可以返回值(支持多个并且组织成元组)
2.函数体代码遇到return直接结束
- 生成器表达式
l = [11, 22, 33, 44, 55, 66, 77, 88, 99]
res1 = (i+1 for i in l if i!=44) # 产生一个生成器
print(res1.__next__)
print(res1.__next__)
print(res1.__next__)
'''迭代器对象、生成器对象可以看作‘工厂’,调用的时候才会加工出数据'''
# 小练习
# 求和
def add(n,i):
return n+i
# 调用之前是函数,调用之后是生成器对象
def text():
for i in range(4):
yield i
g = text() # 初始化生成器对象
for n in [1,10]: # 注意这个位置是列表
g = (add(n,i) for i in g)
res = list(g)
print(res) # [20,21,22,23]