python——生成器和装饰器

本文深入探讨Python中的生成器和装饰器。首先介绍了生成式,包括列表生成式、集合生成式和字典生成式,强调其在处理大量数据时的优势。接着详细阐述了生成器的原理和使用场景,特别是其内存效率特性。然后讲解了装饰器,解释了装饰器的作用、实现原理和应用场景,如日志记录、性能测试、权限验证等,并提到了闭包的概念及其在装饰器中的应用。最后讨论了多装饰器的使用情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、生成式

用来快速生成某一个数据类型的式子

列表生成式[]

需求:已知x=1…10,求y=2x+8,并将求出的所有y值存除到列表中

#1 普通方法
result=[]
for x in range(1..11):
	y=2*x+8
result.append(y)
print(result)
#2 生成式
result = [ 2*x+8 for x in range(1,11) ]
print(result)

列表生成式中的for循环里面可以嵌套if语句,也可以嵌套for语句

需求:判断偶数并计算

result = [ 2*x+8 for x in range(1,11) if x%2==0 ]

使用场景:y=对x做了操作,需要把y存储起来

集合生成式{}

result = {x**2 for x in range{1..11}}

字典生成式{}

result = {key:key**2 for key in range(10)}
print(result)
print(type(result)) 

2、生成器

一边循环一边计算的机制

什么时候需要使用生成器?
性能限制需要用到,比如读取一个10G的文件,如果一次性将10G的文件加载到内存处理的话
(read方法),内存肯定会溢出;但使用生成器把读写交叉处理进行,比如使用(readline和readlines)
就可以再循环读取的同时不断处理,这样就可以节省大量的内存空间.

创建生成器:1)生成式改写() 2)yield关键字
怎么让生成器进行计算? 1) next() 2)通过for循环遍历生成器对象

g=(x**2 for x in range(10))
for item in g:
	print(item)
#next(g)
for x in g:
	print (x)

yield关键字:停靠,让步
函数中遇到yield关键字,函数执行停止,直到调用下一个next函数,从停止的地方继续执行。

def welcome():
	while True:
		print('step1')
		return 'OK'  ##函数中遇到return,函数执行结束,后面的代码不会继续执行
		print('step2')
result = welcome()
print(result)
def welcome():
	count = 1
	while count <= 10:
		prin('step %d' %(count))
		count+=1
		yield 'OK'
g=welcome()
print(next(g))##通过调用next函数才开始执行函数的内容,遇到yield就停止执行
print (next(g))##当再次调用next,从上次停止的地方继续执行,直到遇到yield关键字停止

如果函数中包含yield关键字,调用函数的返回值是生成器,这个时候函数并没有执行

3、装饰器

装饰器: 用来装饰函数或者类的工具, 在不改变源代码的情况下给函数/类添加额外功能.
装饰器装饰的是函数/类,所以需要传递的参数是函数名或者类名。

装饰器的实现必须遵循两大原则:
• 封闭: 对已经实现的功能代码块封闭。 不修改被装饰对象的源代码
• 开放: 对扩展开发
装饰器其实就是在遵循以上两个原则的前提下为被装饰对象添加新功能。

装饰器经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、
权限校验等应用场景。

闭包的概念:

闭包就是指有权访问另一个函数作用域中的变量的函数。
常见形式: 内部函数使用了外部函数的临时变量,且外部函数的返回值是内部函数的引用。
闭包的一个常用场景就是装饰器。
优点: 闭包也具有提高代码可复用性的作用。

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()
		#__name__ 变量(前后两个下划线)是一个特殊的Python变量。它的值取决于我们如何执行包含它的脚本
        print("函数%s执行使用的时间是%.3fs" %(f.__name__, end-start))
        return result
    return wrapper

# 2. 如何去使用装饰器?@装饰器的名称
# @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下载完成.......")
 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
"""
@timeit
def add(num1, num2):
    time.sleep(0.2)
    return num1 + num2
  
print(add(10, 20))

当有多个装饰器时的情景:

import time
from functools import wraps

def welcome(f):
    # wraps装饰器用来保留f函数原有的属性,包括他的帮助信息
    @wraps(f)
     # 这里是可变参数和关键字参数
    def wrapper(*args, **kwargs):
        print("welcome..........")
        result = f(*args, **kwargs)
        return result
    return wrapper

def logger(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)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值