首页 > 代码库 > 装饰器、生成器、迭代器

装饰器、生成器、迭代器

装饰器的前奏

装饰器:本质是函数  功能:就是装饰成其他函数  就是为其他函数添加附加功能的

高阶函数+嵌套函数=装饰器

原则:1、不能修改被装饰的函数的源代码

    2、不能修改被装饰的函数的调用方式  

总结一句话:装饰器对被装饰的函数是完全透明的

实现装饰器的只是储备:

1、函数名即“变量”   将函数体赋值给变量   和内存回收机制一样

2、高阶函数

  2.1.把函数名作为实参传递给形参(可返回被修饰函数的地址)(不修改源代码的情况可添加新的功能)

  2.2返回值中包含函数地址(不修改函数的调用方式),在原函数里需要有返回内存地址
2.1把函数名作为实参传递给形参
import
time def bar(): time.sleep(0.3) print("in the bar") def test(fun): star_time = time.time() fun() end_time = time.time() print("the fun run time is %s"%(end_time-star_time)) test(bar)

2.2返回值中包含函数内容地址,不修改函数的调用方式
import time
def bar():
    star_time = time.time()
    print("in the bar")
def test(fun):
    print(fun)
    return fun      #返回值中包含函数内容地址,不修改函数的调用方式
bar=test(bar)
print(bar)
import time
def test1():
    time.sleep(3)
    print("in the test1")
def bar(fun):
    star_time=time.time()
    fun()
    end_time=time.time()
    print("the fun run time is %s"%(end_time-star_time))
    return fun
test1 = bar(test1)
test1()
结果为:
in the test1
the fun run time is 3.0
in the test1

 

技术分享

3、嵌套函数

在一个函数里又定义了一个函数
def foo():
    print("in the foo")
    def bar():
        print("in the bar")
    bar()
foo()

 

函数即变量名:

技术分享

 

装饰器

import time
def test1():
    time.sleep(3)
    print("in the test1")
def test2():
    time.sleep(3)
    print("in the test2")
def bar(fun):
    star_time = time.time()
    fun()
    end_time = time.time()
    print("the time is %s"%(end_time-star_time))
bar(test1)
bar(test2)        #用函数名赋值给形参


import time
def bar(fun):
    star_time = time.time()
    return fun
    end_time = time.time()
    print("the time is %s"%(end_time-star_time))
def test1():
    time.sleep(3)
    print("in the test1")
def test2():
    time.sleep(3)
    print("in the test2")
test1=bar(test1)
test2=bar(test2)
test1()
test2()         #不改变函数的调用方式
高阶函数+嵌套函数=装饰器
import time
def timer(fun):
    def bar():
        star_time = time.time()
        fun()
        end_time = time.time()
        print("the time is %s"%(end_time-star_time))
    return bar

def test1():
    time.sleep(3)
    print("in the test1")
def test2():
    time.sleep(3)
    print("in the test2")
test1=timer(test1)
test2=timer(test2)
test1()
test2()         #不改变函数的调用方式 为test1、test2 增加了新功能但没有改变原函数的代码
结果为:
in the test1
the time is 3.000171422958374
in the test2
the time is 3.000171661376953

import time
def timer(fun):
    def bar():
        star_time = time.time()
        fun()
        end_time = time.time()
        print("the time is %s"%(end_time-star_time))
    return bar
@timer  #要调用装饰器  在前面加@装饰器的名字
def test1():
    time.sleep(3)
    print("in the test1")
@timer  #要调用装饰器  在前面加@装饰器的名字
def test2():
    time.sleep(3)
    print("in the test2")
# test1=timer(test1)
# test2=timer(test2)      #希望直接用 test2()的格式直接调用,解释器提供了@装饰器的名字
test1()
test2()         #不改变函数的调用方式 为test1、test2 增加了新功能但没有改变原函数的代码
结果为:
in the test1
the time is 3.000171661376953
in the test2
the time is 3.000171661376953

import time
def timer(fun):
    def bar(*args,**kwargs):
        star_time = time.time()
        fun(*args,**kwargs)
        end_time = time.time()
        print("the time is %s"%(end_time-star_time))
    return bar
@timer  #要调用装饰器  在前面加@装饰器的名字
def test1():
    time.sleep(3)
    print("in the test1")
@timer  #要调用装饰器  在前面加@装饰器的名字
def test2(name,age):
    time.sleep(3)
    print("My name is %s ,have %s year old"%(name,age))
# test1=timer(test1)
# test2=timer(test2)      #希望直接用 test2()的格式直接调用,解释器提供了@装饰器的名字
test1()
test2("Mike",18)         #不改变函数的调用方式 为test1、test2 增加了新功能但没有改变原函数的代码
结果为:
in the test1
the time is 3.000171661376953
My name is Mike ,have 18 year old
the time is 3.000171422958374

 带参数的装饰器

_name = "alex"
_pwd = "123"
def login(auth_type):
    def inner(fun):def bar(*wargs,**kwargs):
            if auth_type == "local":
                name = input("name:")
                pwd = input("pwd:")
                if _name==name and _pwd==pwd:
                    print("congratulations!")
                else:
                    print("the usr or pwd is invalid!")
            elif auth_type=="1dap":
                print("the usr in 1dap")
        return bar
    return inner
@login(auth_type="local")
def index(style):
    print("in the index page")
@login(auth_type="1dap")
def home():
    print("in the home page")
def bbs():
    print("in the bbs page")
index()
home()
bbs()

 

 生成器(只有在调用的时候才会准备好数据)

 生成器是边执行边计算  只有调用到对应的数据该数据才会产生(才会生成相应的数据)  和列表生成式的不同在于列表生成式在执行前已经把数据全部放在了内存里 占据了内存

生成器:省内存,因为它只记录当前的位置  对前面、后面的位置数据也是不知道的

生成器方法:只有一个__next__()方法(3.0)

      next()——2.0

 c=(i*2 for i in range(100000)) ————生成器

 

#列表生成式,是代码更简洁
a = []
for i in range(10):
    a.append(i*2)
print(a)
结果为:
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
技术分享
a = (i*2 for i in range(10))     #生成器
#print(a.next())#基本不用next()获取下一个返回值
for i in a:
    print(i)
结果为:
0
2
4
6
8
10
12
14
16
18
生成器

定义generator另一种方法:

#斐波拉契数列,可以从第一个元素开始,推算出后续任意的元素
def fib(num):
    n,a,b = 0,0,1
    while n<num:
        print(b)
        a, b = b, a + b
        n+=1
fib(10)
#和generator仅一步之遥 ,把 print(b) 改成  yield(b)  这个函数就不是普通的函数  而是generator
def fib(num):
    n,a,b = 0,0,1
    while n<num:
        #print(b)
        yield (b)
        a, b = b, a + b
        n+=1
f_gen = fib(10)
print(f_gen)
结果为:<generator object fib at 0x0000000002754F30>

#generator 执行顺序和函数有点区别,区别:每次调用next()执行语句时  遇到yield语句返回,再次执行时是从上一次返回的yield语句处继续执行
def fib(num):
    n,a,b = 0,0,1
    while n<num:
        #print(b)
        yield (b)
        a, b = b, a + b
        n+=1
f_gen = fib(10)
print(f_gen.next())
print(f_gen.next())
print("先打断函数继续运行,做点别的事情")
print(f_gen.next())
结果为:
1
1
先打断函数继续运行,做点别的事情
2

用for循环拿不到generator的返回值,若想拿到要获取到StopIteration错误,返回值包含StopIteration的value中

def fib(num):
    n,a,b = 0,0,1
    while n<num:
        #print(b)
        yield (b)
        a, b = b, a + b
        n+=1
    return "done"
g = fib(6)
while True:
    try:
        x = next(g)
        print(g:, x)
    except StopIteration as e:
        print(Generator return value:, e.value)
        break

 

#通过yield单线程实现并发运算效果
import time
def consumer(name):
    print("%s准备开始吃包子"%name)
    while True:
        baozi = yield
        print("包子%s被%s客户食用"%(baozi,name))
def producer(name):
    c1 = consumer("A")
    c2 = consumer("B")
    c1.next()
    c2.next()
    print("开始准备做包子啦")
    for i in range(10):
        time.sleep(2)
        print("做了1个包子")
        c1.send(i)
        c2.send(i)
producer("Mike")

 

 

 

 

迭代器

1、for循环可以作用于集合数据类型、生成器
集合数据类型:字典、元组、列表、集合、字符串——————这些虽说可迭代对象 但不是迭代器 可通过内置函数iter()变成迭代器
生成器:generator 包括生成器和带yield的generator function
这些作用于for循环的对象称 可迭代对象,Iterable
#字典、元组、列表、集合、字符串是可迭代对象
from collections import Iterable
print(isinstance({},Iterable))
print(isinstance([],Iterable))
print(isinstance(set(),Iterable))
print((isinstance((),Iterable)))
print(isinstance("ABC",Iterable))
**可以被next()函数调用并返回下一个值的对象称为迭代器 Iterator
可以使用isinstance判断一个对象是否是Iterator
生成器一定以个迭代器,但迭代器不一定是生成器

 技术分享

>>> isinstance((i for a in range(10)),Iterator
True
字典、元组、列表、集合、字符串——————这些虽说可迭代对象  但不是迭代器  可通过内置函数iter()变成迭代器
>>> a=[1,2,3]
>>> iter(a)
<list_iterator object at 0x004E5690>

技术分享

 

装饰器、生成器、迭代器