python:三器一闭

162 阅读4分钟

Python中的没有“三器”这一说法,只是可以总结为,三器是指:装饰器,迭代器,生成器。一闭是指闭合器

闭包

高阶函数+嵌套就可以构成一个基本的闭包。

闭包满足条件:

  1. 嵌套函数;
  2. 内层函数引用外层函数的变量;
  3. 内层函数返回内层函数的地址。
def f1(x):
    b=3
    def f2():
        print(b+x)
    return f2
res=f1(10)
print(f1(10))
res()

输出结果:

image.png

由以上结果看出,f1(10)得到的返回值是一个f2函数的地址<function f1..f2 at 0x00000219F707BA60>,并且将f2的函数地址返回给f1,所以f1得到的是一个新的函数地址。

# 可变类型
def fun():         #普通函数
    l1 = []
    l1.append(11)
    print(l1)

def fun1():        #闭包函数
    l2 = []
    def fun2():
        l2.append(11)
        print(l2)
    return fun2
# 普通函数
fun()
fun()
res1=fun1()
res1()
res1()

输出结果:

image.png

由以上结果就可以看出普通函数和闭包函数的区别,普通函数在调用一次之后,不会保存结果,所以每次只会返回一次运行结果。而闭包函数的外层的变量是保存下来了的,调用多少次,就会保存多少次运行结果在里面。

装饰器

装饰器是闭包的一种实现方式

装饰器的作用:在不改变原有函数调用方式的基础上,增加新的功能

@装饰器

定义装饰器:

# 定义装饰器
def zs(f):
    def inner():
        #使用外层函数的变量
        print('大家好,我叫XXX')
        f()  #f函数地址,f()使用函数
    return inner #返回内层函数的地址
@zs
def say_hello():
    print('你好')

say_hello()
say_hello()

输出结果:

image.png

由以上结果看出调用装饰函数之后,每执行一次函数,装饰函数都会跟着运行一次,但并不会改变原有函数的功能,只是在原有功能之上新增一些功能。

l11 = []
def zx_cx(f):      #接收add_std1函数地址
    def inner1():
        f()        #调用接收到的函数地址
        if 'XX' in l11:
            print('已经存在')
        else:
            print('meiyou')
    return inner1

@zx_cx
def add_std1():
    name = 'XX'
    l11.append(name)
    print(l11)

print(add_std1)
add_std1()

输出:

image.png 上述执行过程分析:先执行11行:执行装饰函数器函数,把下方的add_std1的函数名以参数形式传递给zx_cx,早zx_cx中,f接收到了add_atd1的函数地址,zx_cx把内能函数inner1的地址返回给了add_atd1。12行在内存中定义了add_std1函数名,add_atd1指向的是inner1的地址,18行执行的是inner1函数,在inner1里面执行f(),f保存的是add_std1,实际是在执行12行的add_std1(),add_atd1执行完回到第三行,inner1执行完回到第18行。

迭代、可迭代对象、迭代器、生成器

迭代:从容器的第一个元素开始,到最后一个元素

可迭代对象:允许被迭代的对象(可理解为一个容器)

迭代器:访问容器元素的一个对象(访问数据,自己本身没数据

生成器:特殊的迭代器,可自己创建数据和访问数据

from collections.abc import Iterator,Iterable
# 迭代器:Iterator
# 可迭代对象:Iterable
list = [23]
print(isinstance(list,Iterator))
print(isinstance(list,Iterable))

输出:

image.png

dir()

dir()查看变量具有的方式属性

list = [23]
print(dir(list))
print(isinstance(list,Iterable))
print(isinstance(list,Iterator))

输出:

image.png

image.png

当看见输出结果中由iter(),说明该变量是可迭代对象

res = map(lambda x:x**2,[2,3,4,5])
print(isinstance(res,Iterable))
print(isinstance(res,Iterator))
print(dir(res))

输出结果:

image.png image.png

发现res变量不仅是可迭代对象,同时也是迭代器,因为输出结果中含有next()

注意: 可迭代对象不一定是迭代器,但迭代器一定是可迭代对象。

list = [23]
list1 = iter(list)  #iter()拿到可迭代对象的迭代器
print(isinstance(list1,Iterator))
print(isinstance(list1,Iterable))

输出代码:

image.png

生成器

生成器通过**next()**取值

生成器:一般边生成边计算

#第一种方法
g1 = (i for i in range(10))   #生成器,里面没有数据,可以省内存
print(g1,type(g1))
l1 = [i for i in range(10)]
for i in l1:
    print(i)

输出结果:

image.png

#第二种方法   生成器函数,用yield返回值
#return即是返回值的意思,也是结束代码执行的意思
def g2():
    yield 1

def g3():
    return 1

print(g2())
print(g3())

输出代码:

image.png

#第二种方法   生成器函数,用yield返回值
#return即是返回值的意思,也是结束代码执行的意思
def g2():
    yield 1
    yield 2
    yield 3
    yield 4

print(g2())   #拿到返回值,返回g2地址
res=g2()
print(next(res))
print(next(res))
print(next(res))
for i in res:
    print(i)

输出结果:

image.png