python基础——5.闭包,迭代器,装饰器,生成器


1.闭包:嵌套函数,内部函数调用了外部函数的变量
def outer():
a = 1
def inner():
print(a)
print(inner.closure)
outer()
# 只要打印函数的__closure__方法,有cell就是闭包

全局变量有可能被修改,全局变量是不安全的.用闭包可以保护我们的变量
写法:在外层函数中声明一个变量,在内层函数使用或者返回这个变量
闭包的应用,保护变量,常驻内存(全局变量也可以让变量常驻内存)

2.装饰器:不想修改函数的调用方式,但是还想在原来的函数前后添加功能
开放封闭原则;对扩展是开放的;对修改是封闭的;不让修改称之为封板
def timmer(f):
def inner():
start = time.time()
ret = f()
end = time.time()
print(end-start)
return inner
@timmer # 语法糖
def func():
time.sleep(1)
print("123")
ret = func()

# 原始写法
# func = timmer(func)
# func()

3.带参数的装饰器
flage = true
def timmer_out(flage):
def timmer(func):
def inner(args, **kwargs):
if flag:
start = time.time()
ret = func(
args, **kwargs)
end = time.time()
print(end-start)
return ret
else:
ret = func(*args, **kwargs)
return ret
return inner
return timmer
@timmer_out(flage):
def func():
tim.sleep(1)
print("ok")
# 首先调了一个timmer_out(flage)理解成@和timmer_out(flage)分两步走

4.多个装饰器装饰一个函数
def wrapper1(func):
def inner1():
print("wrapper1, before func")
func()
print("wrapper1, after func")
return inner1

def wrapper2(func):
    def inner2():
        print("wrapper2, before func")
        func()
        print("wrapper2, after func")
    return inner2
@wrapper2
@wrapper1
def f():
    print("in f")
f()

5.打散聚合
def outer(args):
print(args)
print(
args)
outer(1, 2, 3, 4) # == outer([1, 2, 3, 4]) == outer((1, 2, 3, 4))

# print(*args)返回的不是元组
# 原理是print函数带*arg参数

6.迭代器
只要含有__iter__方法的都是可迭代的--可迭代协议
迭代器协议--内部含有__next__和__iter__方法的都是迭代器

可迭代的.__iter__()方法可以得到一个迭代器
迭代器的.__next__()方法可以一个个的获取值

特征:1.节省内存 2.惰性机制 3.只能向前

7.生成器
生成器的本质就是迭代器,写法和迭代器一样
优点:1.节省内存,几乎不占内存 2.惰性机制 3.只能向前
生成器由生成器函数来创建或者通过生成器表达式来创建
在函数中return换成yield这个函数就是生成器函数
如何从生成器中取值:for next send 数据类型强制转换

def func():
    for i in range(100):
        yield "蛋%s" % i
func().__next__()
func().__next__()

def func():
    print("123")
    a = yield "abc"
    print("234", a)
    b = yield "bcd"
    print("345", b)
    yield "456"
gen = func()
gen.__next__()

def generator():
    print(123)
    content = yield 1
    print("------", content)

    print(456)
    content2 = yield 2
    print("------", content2)

    print(789)
    yield 3

g = generator()
ret = g.__next__()
print(ret)
ret = g.send("hello")
print(ret)
ret = g.send("hello2")
print(ret)

## send获取下一个值的效果和next基本一致
## 只是在获取下一个值的时候给上一个yield的位置传递一个参数
## 第一次使用生成器只能用next获取值;最后一个yield不能接收外部的值(所以可以最后加一个yield)

# 计算移动平均值
# 1.count计数 2.sum求和 3.avg平均值
# def init(average):
#     def inner(*args, **kwargs):
#         g = average(*args, **kwargs)
#         g.__next__()
#         return g
#     return inner
#
# @init
# def average():
#     sum = 0
#     count = 0
#     avg = 0
#     while 1:
#         num = yield avg
#         sum += num
#         count += 1
#         avg = sum/count
#
# g = average()
# print(g.send(10))
# print(g.send(20))
#
# for i in [4, 5, 88, 9, 98, 66]:
#     print(g.send(i))

## 生成器表达式
    (条件成立想放在生成器中的值) for i in 可迭代的 if 条件
    g = (i for i in range(10))
    # 与列表推导式的区别 括号不一样 返回的值不一样