Python 装饰器、迭代器、生成器

装饰器

what 是装饰器

定义一个函数,该函数用于装饰其他函数,使得被装饰函数增加额外的功能而不用修改内部代码。装饰器的写法为:“@装饰器”。

why 要用装饰器

符合开放封闭原则,即:
开放:有新的需求时,函数是可以被扩展的。
封闭:函数一旦设计完成,就可以独立工作,不可对其内部进行修改。
故装饰器就是在不改变被装饰函数内部代码的情况下,为其添加新功能。通常用于以下场景:插入日志、性能测试、事务处理、缓存、权限检验等。

how 使用装饰器

  • 前置1—函数作为实参传入到另一个函数内
def func1(func):
	print("start func1...")
	res = func()
	print("end func1...")
	return res
def func2():
	print("start func2...")
	print("end func2...")
func1(func2)
#### 结果
start func1...
start func2...
end func2...
end func1...
  • 前置2—函数嵌套,在一个函数内定义另一个函数,并将其作为返回值
def func1(func):
	print("start func1...")
	def innerFunc(*args, **kwargs):
		print("this is inner function...")
		res = func(*args, **kwargs)
		print("inner function end...")
		return res # 返回执行func后的返回值
	print("end func1...")
	return innerFunc # 返回内部函数
def func2():
	print("start func2...")
	print("end func2...")
print("start:")
print("func2 name: ", func2.__name__, "\n")
print("To decorate:")
func2 = func1(func2)
print("end:")
print("func2 name: ", func2.__name__, "\n")
func2()
#### 输出结果
start:
func2 name:  func2 
To decorate:
start func1...
end func1...
end:
func2 name:  innerFunc  # func2 指向的函数修改为内部函数innerFunc了
this is inner function...
start func2...
end func2...
inner function end...
  • 函数装饰器(修饰函数无参)
import time
def CalTime(func):  # 计算执行函数func用时
    def innerFunc():
        t_start = time.time()
        func()
        t_end = time.time()
        print("Used time: {0}s...".format(t_end-t_start))
    return innerFunc
# 装饰器 CalTime装饰函数func2,在不改动func2函数内部代码及原始功能的情况下添加计时功能。
# 等价于:func2 = CalTime(func2),此时func2将指向innerFunc()
@CalTime
def func2():
    time.sleep(3)
    print("{0}s end...".format(3))
func2()
#### 输出结果
3s end...
Used time: 3.006950855255127s...
  • 函数装饰器(修饰函数带参)
  • 多个函数装饰器
def log1(func):
    print("log1 begin...")
    def inner():
        print("log1-inner begin...")
        func()
        print("log1-inner end...")
    return inner
def log2(func):
    print("log2 begin...")
    def inner():
        print("log2-inner begin...")
        func()
        print("log2-inner end...")
    return inner
@log1
@log2
def func2():
    print("func2 begin...")
    print("func2 end...")
func2()
#### 输出结果
log2 begin...
log1 begin...
log1-inner begin...
log2-inner begin...
func2 begin...
func2 end...
log2-inner end...
log1-inner end...
  • 类装饰器
    类装饰器是返回一个增加了新功能的函数对象,这个函数对象是类的一个实例。由于装饰器必须是可调用对象,因此类内必须实现 __call__ 方法,再对实例使用 () 就可以运行了。
import time
class Decorator:
    def __init__(self, func):
        self.func = func
    def delay_time(self, time_sec):  # 带参数的类装饰器
        time.sleep(time_sec)
        print("延时{0}s结束...".format(time_sec))
    def __call__(self, time):
        self.delay_time(time)
        self.func()
@Decorator
def func2():
    print("延时后开始执行...")
func2(3)  # 此处的参数 3 被传入到__call__()方法内,并传递给delay_time的实参
#### 输出结果
延时3s结束...
延时后开始执行...

参考

Python 装饰器浅析
Python 装饰器详解

迭代器

what 是迭代

迭代:通过重复执行某个操作,不断获取被迭代对象中的数据,这样的每一次操作就是一次迭代。

what 是迭代器 iterator

迭代器就是一个具有迭代功能的对象,使用迭代器可以完成迭代操作。通常迭代操作是通过内置函数 iter()、next() 来完成的。
for 循环的迭代过程分为三步:

  • 对一个容器调用iter()函数,获取迭代器;
  • 每次循环时对迭代器调用next()函数来获取一个值;
  • 在捕捉到StopIteration异常时结束迭代。

可迭代对象的识别:列表、元组、字符串、集合、字典都是可迭代对象。判断一个对象是否是可迭代对象,有两种方式:

  • 通过内置函数dir()获取该对象所有方法,检查是否有 "__ iter__ ",也即是否有__iter__()方法。
  • 使用内置函数isinstance()判断对象是否为Iterable的对象
'__iter__' in dir(对象)

from collections.abc import Iterable
isinstance(对象, Iterable)

自定义迭代器

只需要在类中定义 “__ iter__()” 和 "__next__()"方法即可。此时该类对象支持 迭代器协议

class myIterator:
	def __next__(self):
		<your coding>
	def __iter__(self):
		return self

生成器 Generator

why 有生成器

生成器继承于迭代器,因此生成器拥有迭代器的所有特性。列表和列表生成式中的数据都保存在内存中,当列表中的元素巨大时,将占用大量内存,从而导致内存溢出。因此有了生成器。

what 是生成器

生成器是一个对象,没有保存列表中的数据,而是保存了产生元素的算法,同时记录游标的位置来确定当前输出到哪个元素了。每次调用都会返回一个元素,可以通过 next() 方法获取,这种方式既有列表的优势,又不占用空间。

how 创建生成器:

函数式或者生成器表达式(推导)。

函数式

函数式生成器就是一个函数,特殊之处在于将"return" 改为了 “yield”。当生成器函数运行至"yield"时,将返回 yield 后的结果,并且记录下此时函数运行的位置,下次调用时从该位置的下一步开始执行,直到最后抛出 StopIteration 异常执行完毕。生成器会默认调用__iter__()和__next__()方法。

def my_generator():
	for num in range(11):
		yield 2 ** num
p = my_generator() #调用生成器
next(p) #  在 yield 处停止,并返回 1 (2 ** 0).
生成器表达式(推导)
生成器 = (对项的操作 forin 可迭代对象 if 对项的判断)
# 相当于执行以下步骤:
new_list = []
forin 可迭代对象:
	if 对项的判断:
		新项 = 对项的操作
	new_list.append(新项)
# 集合{}, 字典{key:value}, 生成器() 和列表生成式一样,只是外围的括号不一样。
[如何遍历生成器的元素]
next(<生成器对象>) 
forfor val in g: print(val)
<生成器对象>.next():内置的 __next__,当已经遍历到对象末尾时,会抛出StopIteration异常
	生成器对象的方法:
	.close():关闭生成器
	.send()# 和 next() 一样可以用来生成数据,但可以往生成器内部传递数据(可以和生成器内部进行交互)。
	# 执行next()和send()时都会在yield处暂停,并返回后边的值。
	# 使用send()前必须至少调用一次next()来生成一次数据(或是启动生成器),使生成器内部停留于yield处。
	# 而send()向生成器内部传递的数据将在yield处赋值,将传递进去的参数作为被挂起的yield语句的返回值,示例如下:
	def writer():
	    while True:
	        data = yield
	        print("data: ", data)
	def producer():
	    it = writer() # 返回生成器
	    it.__next__()
	    for i in range(5):
	        print("send data: %d" %i)
	        it.send("%d" %i)
	producer()
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值