Python基础学习(十三)--迭代器,生成器,闭包,装饰器,@property

本文深入探讨了迭代器和生成器的概念,解释了它们在Python中的工作原理,包括如何使用迭代器节约内存,生成器函数的特点及其实现,以及send()和yield from的高级用法。同时,文章还介绍了装饰器的作用和实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、迭代器

(一)什么是迭代器

迭代是访问集合元素的一种方式。拥有__iter__方法和__next__方法的对象就是迭代器。

只要含有__iter__()的都是可迭代的。

# 查看共有方法
print(set(dir([]))&set(dir(''))&set(dir({}))&set(dir(range(2))))

说明int类型不可迭代:

print('__iter__'in dir(int))    # False
a=set(dir([].__iter__()))
b=set(dir([]))
print(a-b)    # {'__next__', '__setstate__', '__length_hint__'}

# __length_hint__--获取元素的个数
# __setstate__--决定取值的位置
# __next__--获取元素

__iter__()作用:返回一个迭代器。

__iter__()中有一个__next__()方法,这个方法可以迭代。

k=[1,2,3]
d=k.__iter__()
print(d.__next__())
print(d.__next__())
print(d.__next__())

(二)for循环原理

1.for循环一个可迭代的对象(实现__iter__()方法)。

2.__iter__()方法返回一个迭代器(迭代器实现了__init__()和__next__())。

3.for先判断对象是否可迭代,然后调用迭代器的__next__()方法获取值。

(三)迭代器作用

节约内存,取的时候再生成数据。

(四)应用场景

1.数据类型转换

str1='hello'
lst1=list(str1)
print(lst1)

tuple1=('a','b','c')
lst2=list(tuple1)
print(lst2)

2.斐波那契序列

class Fib():
    def __init__(self,num):
        self.num=num
        self.a=1
        self.b=1
        self.current=1
    def __iter__(self):
        return self
    def __next__(self):
        if self.current<=self.num:
            print(self.a)
            self.a,self.b=self.b,self.a+self.b
            self.current+=1
        else:
            raise StopIteration
for x in Fib(10):
    pass

二、生成器

生成器的本质就是迭代器。

生成器包括两种:生成器函数和生成器表达式。

(一)生成器函数

一个包含yield关键字的函数就是一个生成器函数。

yield和return不能共用,且yield只能存在于函数中。

1.生成器函数执行之后会得到一个生成器作为返回值,并不会执行函数体。

2.执行了__next__()方法之后才会执行函数体,并且获得返回值。

3.next()内置函数,内部调用生成函数的__next__()方法。

4.yield和return相同的是可以返回值,但是不同的是yield不会结束函数。

def shengchan(n):
    i=1
    while i<=n:
        yield i
        i+=1
x=shengchan(5)
print(x)
# for y in x:
#     print(y)

print(x.__next__())
print(x.__next__())
print(next(x))
print(next(x))
print(x.__next__())
def dee():
    yield 1
    yield 2
    yield 3
x=dee()
print(x.__next__())
print(next(x))
print(next(x))

应用

斐波那契数列:

def fib(n):
    a,b=1,1
    i=1
    while i<=n:
        yield a
        a,b=b,a+b
        i+=1
for x in fib(10):
    print(x)

(二)send()

使用send()的注意事项:

1.第一次使用生成器的时候,是用next获取下一个值。

2.最后一个yield不能接手外部的值。

def g():
    print('a')
    x = yield 10
    print('接收到数据', x)
    yield x + 5    # 最后一个yield不能赋值
x = g()
print(next(x))    # 第一次使用生成器要用next()
b = x.send(999)
print(b)

应用:

计算平均值,送几个,算几个:

def g():
    count=1
    get_num=0
    avg=0
    total=0
    while True:
        get_num=yield avg
        total=total+get_num
        avg=total/count
        count+=1
x=g()
next(x)
print(x.send(10))
print(x.send(20))
print(x.send(30))

(三)yield from

# 使用for循环取出生成器中所有的值
def gen1():
    for c in 'AB':
        yield c
    for i in range(3):
        yield i
for x in gen1():
    print(x)
# 使用yield from
def g():
    yield from 'AB'
    yield from range(5)
for x in g():
    print(x)

(四)生成器表达式

b=(i for i in range(5))
print(b)
for x in b:
    print(x)
a=('鸡蛋%d个'%(i+1) for i in range(10))
print(a)
# next记录了当前的状态
print(next(a))
print(a.__next__())
print(list(a))    # 从第三个开始

三、装饰器

(一)闭包

要求:

1.闭包函数必须有内嵌函数

2.内嵌函数必须要引用外层函数的变量

3.闭包函数返回内嵌函数的地址(函数名称)

重点!!闭包会保留资源,不释放。

def out(b):
    a=3
    def inside(x):
        return a*x+b
    return inside
func=out(3)
print(func(3))

判断闭包函数的方法__closure__

def out(b):
    a=3
    def inside(x):
        return a*x+b
    print(inside.__closure__)    # 有cell元素,是闭包
    return inside
func=out(3)
print(func(3))
def out():
    b=9
    def inner():
        print('haha')
    print(inner.__closure__)    # None--不是闭包
    return inner
x=out()
x()

 这里有一个之前说过的问题,在了解了闭包后会更加好理解。 

def func():
    x=4
    lst=[]
    for i in range(3):
        action=lambda x,i=i:x**i
        lst.append(action)
    return lst
b=func()
print(b[0](2))    # 1
print(b[1](2))    # 2
print(b[2](2))    # 4

b=[lambda x,i=i:x**i for i in range(3)]
print(b[0](2))    # 1
print(b[1](2))    # 2
print(b[2](2))    # 4

(二)装饰器

装饰器的本质:一个闭包函数。

作用:在不修改原函数及其调用方式的情况下对原函数功能进行拓展。

import time
def decor(f):
    def inner():
        t=time.time()
        f()
        t2=time.time()
        print('运行时间:{}'.format(t2-t))
    return inner
@decor
def func():
    s=0
    for i in range(1000000):
        s+=1
    print(s)
func()

添加多个装饰器:

def decor(f):
    def inner():
        print('****')
        f()
        print('****')
    return inner
def decor2(f):
    def inner():
        print('####')
        f()
        print('####')
    return inner

@decor
@decor2
def f1():
    print('欢迎')

@decor
def f2():
    print('走好')

f1()
print()
f2()

创建带参数和返回值的装饰器:

from functools import wraps
def decor(f):
    @wraps(f)    # 解决被装饰函数不能查看信息的bug
    def inner(a,b):
        print('*******')
        d=f(a,b)
        print('*******')
        return d
    return inner
@decor
def func(a,b):
    '''
    :param a:
    :param b:
    :return:
    '''
    c=a+b
    return c
print(func(2,3))
print(func.__doc__)

(三)@property装饰器

 

把一个方法的调用方式变为属性调用方式(将一个方法当成一个属性使用)。

只能在面向对象中使用。

只能修饰不带参数的方法。

class A():
    def __init__(self,name):
        self.name=name
    @property    # 把方法作为属性使用
    def age(self):
        return self.__age    # 属性不能与函数名重名
    @age.setter
    def age(self,age):
        if age<0 or age>100:
            print('错误')
            self.__age=-1
        else:
            self.__age=age
a=A('张三')
a.age=39
print(a.age)
a.age=400
print(a.age)
class A():
    def __init__(self,name):
        self.__name=name
    @property
    def name(self):
        return self.__name
    @name.setter
    def name(self,name):
        self.__name=name
a=A('张三')
print(a.name)
a.name='李四'
print(a.name)

求圆的面积和周长

from math import pi
class Circle():
    def __init__(self,r):
        self._r=r
    @property
    def c(self):
        return 2*pi*self._r
    @property
    def area(self):
        return pi*self._r*self._r
y=Circle(1)
print(y.c)
print(y.area)

BMI指数计算

class Person():
    def __init__(self,name,w,h):
        self.name=name
        self.weight=w
        self.height=h
    @property
    def bmi(self):
        return self.weight/(self.height**2)
p=Person('吕佳',48,1.63)
print(p.bmi)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值