python中的生成式、生成器、闭包、装饰器、异常处理机制
程序员文章站
2022-06-11 22:02:12
...
1.生成式
用来快速生成指定模式的工具
1) 列表生成式[]
#eg1:已知:x=1..10,求y=2x+8,并将求出的所有y值存储到列表中
result = []
for x in range(1,11):
y = 2*x+8
result.append(y)
print(result)
#eg2:x=2,4,6,8,10,求y
#method1:
result = [ 2*x+8 for x in range(2,11,2)]
print(result)
#method2:
result = [ 2*x+8 for x in range(1,11) if x%2==0 ]
print(result)
2) 集合生成式{}
result = {x**2 for x in range(1,11)}
print(result,type(result))
2) 字典生成式{}
result = {key:key+2 for key in range(10)}
print(result,type(result))
2.生成器
在Python中,一边循环一边计算的机制,称为生成器:Generator。
1.什么叫生成器?
在Python中,一边循环一边计算的机制,称为生成器:Generator。
2.什么时候需要使用生成器?
性能限制需要用到,比如读取一个10G的文件,如果一次性将10G的文件加载到内存处理的话(read方法),
内存肯定会溢出;但使用生成器把读写交叉处理进行,比如使用(readline和readlines) 就可以再循环读
取的同时不断处理,这样就可以节省大量的内存空间.
3.生成器的创建
1) 生成式改写
#平方生成器
g = (x**2 for x in range(11))
for item in g:
print(item)
2)yield关键字
#return关键字的含义:函数遇到return,函数执行结束,后面的代码不会继续执行
def welcome():
while True:
print("step 1")
return "ok"
print("step2")
result = welcome()
print(result)
#输出为 step1
# ok
#函数遇到yield,函数执行停止,直到调用下一个next函数,从停止的地方>继续执行
def welcome():
count = 1
while count <= 10:
print("step %d" %(count))
count += 1
yield "ok"
g = welcome()
print(next(g))
print(next(g))
print(next(g))
yield运行结果
3.闭包
1.什么是闭包?
当一个函数在内部定义函数,并且内部的函数应用外部函数的参数或者局部变量,当内部函数被当做返
回值的时候,相关参数和变量保存在返回的函数中,这种结果,叫闭包
2.闭包需要满足三个条件:
1)函数里面嵌套函数
2)内部函数使用外部函数的变量
3)外部函数的返回值是内部函数的引用
# 注意!!:定义函数不执行函数里的代码,调用函数时才执行函数里的代码
def timeit(name):
#wrapper包装纸
def wrapper():
print(name)
return "ok"
return wrapper
result = timeit("westos")
print(result)
4.装饰器
1)什么是装饰器?
装饰器其实就是一个闭包,把一个函数当作参数然后返回一个替代版函数。
在不改动函数代码的基础上无限制扩展函数功能的一种机制,本质上讲,装饰器是一个返回函数的高阶函数
-装饰器的使用: 使用@语法, 即在每次要扩展到函数定义前使用@+函数名
python装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象(函数的指针)。装饰器函数的外部函数传入我要装饰的函数名字,返回经过修饰后函数的名字;内层函数(闭包)负责修饰被修饰函数。从上面这段描述中我们需要记住装饰器的几点属性,以便后面能更好的理解:
2) 装饰器的性质
(1)实质: 是一个函数
(2)参数:是你要装饰的函数名(并非函数调用)
(3)返回:是装饰完的函数名(也非函数调用)
(4)作用:为已经存在的对象添加额外的功能
(5)特点:不需要对对象做任何的代码上的变动
import time # 时间处理模块
import requests # HTTP请求库,多用于网络爬虫, 需要pip install 下载的
# 1). 如何去创建装饰器?
# 需求: 添加功能-计算被装饰函数运行的时间的工具
def timeit(f):
"""
添加被装饰函数执行的时间
"""
# *args和**kwargs是形参还会实参?形参
# *args:可变参数, 可以接收多个参数信息,一般存储到元组中
# **kwargs:关键字参数,可以接收多个键值对信息,一般存储到字典中
# wrapper(10, 20) 接收时用元组来存储(10, 20)
def wrapper(*args, **kwargs):
# 函数执行之前计算当前的时间戳
start = time.time()
# 调用被装饰的函数,并保存函数的返回值
# *args和**kwargs是形参还是实参? 实参
# 注意: 这里不是可变参数的意思,是解包的意思.args=(10, 20) *args=10,20
# f(10, 20)==add(10,20)
result = f(*args, **kwargs)
# 函数执行之后计算当前的时间戳
end = time.time()
print("函数%s执行使用的时间是%.3fs" %(f.__name__, end-start))
return result
return wrapper
# 2. 如何去使用装饰器[email protected]装饰器的名称
# @timeit的工作原理: download_music=timeit(download_music)
# 执行的过程:
# 1). timeit(download_music)函数的返回值是wrapper函数名.
# 2). download_music=timeit(download_music), 让download_music=wrapper
# 3). 最后一行download_music(),实质上执行的函数wrapper()
# 4). 执行wrapper函数时, f()实质上执行的函数download_music()
@timeit
def download_music():
url = "http://m10.music.126.net/20200719111612/e36c0e235dbad219e9d8f0e65fa62007/ymusic/0201/7233/bea2/2cb43c8bcaa7797d32e5ca9b831350d8.mp3"
# 模拟浏览器访问mp3的网址,获取服务器端给我们的响应(response)
response = requests.get(url)
# 获取mp3音乐的内容
# music_content = response.content
# 打开文件,存储音乐的内容到文件中
with open("再见.mp3", 'wb') as f:
f.write(response.content)
print("再见.mp3下载完成.......")
@timeit
def add(num1, num2):
time.sleep(0.2)
return num1 + num2
download_music()
"""
分析add函数执行的过程:
1. add(10, 20)调用函数
2. 发现add函数被装饰器timeit装饰了, @timeit==> add=timeit(add)
3. timeit(add)函数的返回值是wrapper函数, add=timeit(add)这里add=wrapper
4. 终于知道add函数是什么了.add(10, 20)===> wrapper(10, 20)
5. 在wrapper函数中有f()===> add(10, 20)
6. 返回f()函数的返回值30
"""
print(add(10, 20))
3)装饰器模板
#编写装饰器的模板
# 1) 先实现闭包
# 2) 要让这个装饰器可以装饰所有函数/类(代表函数可以接收有参数/无参数)
# 3) 如何让被装饰的函数保持自己原有的帮助信息
import time
from functools import wraps
def welcome(f):
@wraps(f)
def wrapper(*args, **kwargs):
print("welcome..........")
result = f(*args, **kwargs)
return result
return wrapper
def logger(f):
# 这里是可变参数和关键字参数
# wraps装饰器用来保留f函数原有的属性,包括他的帮助信息
@wraps(f)
def wrapper(*args, **kwargs):
"""
wrapper function
"""
start = time.time()
# 这里是解包
result = f(*args, **kwargs)
end = time.time()
print("Logger: %s %s run %.3f s" %(time.ctime(), f.__name__, end-start))
return result
return wrapper
# 多个装饰器装饰的时候, 从下向上进行装饰的, 执行的时候是从上到下进行执行.
@welcome
@logger # add = logger(add)====> add=wrapper
def add(num1, num2):
"""
add function
"""
time.sleep(0.1)
return num1 + num2
result = add(10, 20)
print(result)
#print(help(add))
5.异常处理机制
try:
print("可能出现异常的代码")
li = [1,2,3,4]
print(li[9])
except IndexError as e:
print("出现索引异常")
print(li[-1])
else:
print("没有出现异常")
finally:
print("不管是否有异常,都会执行的内容")