迭代器,生成器,装饰器的理解

迭代器

迭代器是一个记录了当前获取可迭代对象数据的位置,然后在下一次获取数据的时候自动的往前获取下一位 , 可以将一个可迭代对象中的数据全部获取一遍, 一般可以进行for循环的对象都是可迭代对象
如,列表, 字符串, 元组等

在一个类中,只要实现了__iter__方法的对象都是可迭代对象, 在实现__iter__的前提再实现__next__方法的对象就是迭代器了

# 可迭代对象就是可以 for in 遍历的数据,如,list dict str 这些都是可迭代对象
# 在一个类中,只要实现了 __iter__ 方法,那么,通过这个类创建出来的实例对象就是一个可迭代对象
# 在一个类中不仅实现了__iter__ 方法,还实现了 __next__ 方法时, 这个类就是一个迭代器
# 迭代器一定是可迭代对象,而可迭代对象并不一定是迭代器
# 判断一个对象是否是可迭代对象是,可以使用 collections 中的 Iterator 类来判断
# print(isinstance(要判断的对象, Iterable)), 结果不是True 就是 False

# 判断一个对象是否是迭代器,可以使用 collections 中的 Iterator 进行判断
# print(isinstance(要判断的对象, Iterator)), 结果不是True 就是 False
# 也可以使用 for in 来进行判断,在for 条件中要判断的对象如果没有报黄色背景颜色的话,那么
# 它就是一个可迭代对象


from collections import Iterator, Iterable


class A:
    def __init__(self):
        self.data = [10, 20, 30, 40]
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        # 判断当前要获取数据的下标是否超出了这个总数
        if self.index < len(self.data):
            # 记录当前数据的下一个数据的下标
            self.index += 1
            # 返回迭代的数据
            return self.data[self.index - 1]
        # 当获取到要迭代的数据的最后一个数据的时候,将记录下标设置为0
        self.index = 0
        # 抛出异常,停止迭代
        raise StopIteration

class B:
    def __iter__(self):
        pass


a = A()
b = B()
print("a 对象是否是一个可迭代对象", isinstance(a, Iterable))   # a 对象是否是一个可迭代对象 True
print("a 对象是否是一个迭代器", isinstance(a, Iterator))   #  a 对象是否是一个迭代器 True
print("b 对象是否是一个可迭代对象", isinstance(b, Iterable))  # b 对象是否是一个可迭代对象 True
print("b 对象是否是一个迭代器", isinstance(b, Iterator))  # b 对象是否是一个迭代器 False


# __iter__的作用,当for 循环这个可迭代对象的时候,会先到这个可迭代对象中调用__iter__ 方法,
# 当调用完这个方法后,__iter__ 返回一个迭代器对象,可以返回self 本身,也可以返回一个新的迭代器
# 对象, for 会到返回的对象中调用 __next__ 方法进行获取数据, 当for 循环这个__next__ 方法抛出异常
# 停止迭代的时候,for 函数内部有异常捕获的处理,当捕获到这个异常的时候,就跳转迭代
for i in a:
    print(i)

生成器

生成器是一个可以一边循环,一边生成新的数据的对象, 可以根据算法生成自己想要的数据, 不占用内储空间, 由于它也是一边生成一边记录的对象,使用,生成器也是特殊的迭代器
创建生成器:
1 列表推倒式的[] 改为 ()

from collections import Generator


def A():
    yield


a = A()
print("a是否是一个生成器:", isinstance(a, Generator))  # a是否是一个生成器: True

这就是一个生成器了

2 在函数中使用 yield 关键字
yield关键字可以暂停函数的执行并且返回数据,不像return, return是直接将函数跳转运行 如

def a():
    num = 0
    while True:
        num += 1
        yield num


b = a()
print(next(b))
print(next(b))
print(next(b))

这个a函数就是一个生成器
生成器可以通过next进行唤醒进行执行,也可以通过send进行唤醒,通过send唤醒的好处就是可以向生成器中发送数据, 如

def a():
    num = 0
    nums = 0
    while True:
        num += 1
        nums = yield nums


b = a()
print(next(b))
print(b.send(8520))
print(b.send(10))

这里需要注意,在没有进行第一次调用b的时候需要next进行调用一次或send传递一个None进去或者调用一次next(g)方法,才能进行传值操作,不然会出现异常, 因为send作用是将原yield 暂停的位置唤醒继续执行,如果直接执行send 并传送数据的话,函数并没有执行到yield 那里,所以就会出现异常,如果是传递None的话,就相当于调用 next() 方法执行一遍生成器,作用不会出现异常

闭包

闭包就是函数的嵌套, 外部函数返回内部函数的引用, 内部函数使用到外部函数的局部变量
闭包内的值不会先其他函数一个会随着函数调用的结束而释放内存,它会一直常驻内存
次时a函数就是一个闭包

def a():
    num = 0

    def b():
        print(num)

    return b

装饰器

装饰器就是闭包的使用, 在程序写完后,我们如果想对某个函数进行功能的添加的时候,我们可以使用装饰器,这样可以在不修改代码的前提下对函数添加新功能,在日常使用中在函数打印的上一级写上@加上一个闭包的引用就做到了装饰器的效果了, 如

def a(aa):

    def b():
        print("要装饰的函数是: ", aa)
        print("闭包被调用了,")
        return aa()
    return b


@a
def c():
    print("这个是正常的函数")


c()

在这里插入图片描述
可以看到,在对函数进行装饰后,在调用函数的时候会先调用装饰器
这样我们就可以给函数添加新功能了
闭包和装饰器的区别, 闭包是将外部函数的变量当做数据来使用, 而装饰器是将外部函数的变量当做方法来调用

装饰有参函数

当需要装饰有参函数的时候,需要将装饰器中的内部函数写上形参接收装饰函数的参数, 建议在内部函数中使用 *args**kwargs这种不定长参数来接收

def a(aa):

    def b(*args, **kwargs):
        print("要装饰的函数是: ", aa)
        print("闭包被调用了,")
        aa(*args, **kwargs)
    return b


@a
def c(name):
    print("这个是正常的函数, 它的name参数是:", name)


c(name="laowang")

装饰有返回值参数

当要装饰的函数是一个有return 的函数的时候,需要在装饰器中内部函数调用要装饰的函数中 return

def a(aa):

    def b(*args, **kwargs):
        print("要装饰的函数是: ", aa)
        print("闭包被调用了,")
        return aa(*args, **kwargs)  
        # 在这里return 要调用的函数,这样会先调用aa(*args, **kwargs),当aa 函数调用完成后,
        # 此时 return 后面就有了aa 函数的返回值了,再将这个返回值个返回到外部调用方法上
    return b


@a
def c(name):
    print("这个是正常的函数, 它的name参数是:", name)
    return 10


c(name="laowang")

装饰器带参数
def a(*args, **kwargs):
    def b(func):
        def c(*args, **kwargs):
            print("装饰器传递过来的参数是: ", *aa, *kwargs)
            print("闭包被调用了,")
            return func(*args, **kwargs)
        return c
    return b


@a("eiofewoweao")
def c(name):
    print("这个是正常的函数, 它的name参数是:", name)
	return 10

c(name="laowang")

可以看到,当装饰器要携带参数的时候, 装饰器的嵌套就变成了三层了, 最外部 a 函数接收装饰器 a 传递过来的参数, 内部函数 b 接收要装饰的函数, c 函数接收要装饰的函数的 参数

多个装饰器装饰同一个函数
def a(func):
    def c(*args, **kwargs):
        print("a装饰器被调用了,")
        nums = func(*args, **kwargs)
        print("a装饰器中的nums 返回值是: ", nums)
        return nums
    return c


def b(func):
    def c(*args, **kwargs):
        print("b装饰器被调用")
        nums = func(*args, **kwargs)
        print("b装饰器中的nums 返回值是: ", nums)
        return nums
    return c

@a
@b
def c(name):
    print("这个是正常的函数, 它的name参数是:", name)
    return 10


c(name="laowang")

在这里插入图片描述
可以看到,最上层的装饰器被先调用, 当装饰器a 函数中 执行到 nums = func(*args, **kwargs)语句的时候,会调用 b 装饰器,b装饰器调用到 nums = func(*args, **kwargs)时才会真正的调用到要装饰的函数
然后 执行完 nums = func(*args, **kwargs)后将 正常函数中的返回数据进行 return 到a 装饰器,a 装饰器接着将这个返回值给返回到调用函数上

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值