Python学习第七天

本文详细介绍了迭代器、生成器和装饰器的概念及使用方法。迭代器简化循环并节省内存,自定义迭代器通过`__iter__`和`__next__`方法实现。生成器通过`yield`关键字创建,按需生成序列,节省内存。装饰器则提供了一种增强函数或类功能的方式,通过`@decorator`语法实现。文中给出了多个示例,展示了如何创建和使用这些概念。
摘要由CSDN通过智能技术生成

迭代器、生成器与装饰器

迭代器

迭代器定义

迭代器的使用简化了循环程序的代码并可以节约内存,生成器的使用也可以节约大量的内存,特别是需要生成大量序列的对象时。迭代器 是一种可以从其中连续迭代的一个容器,如前文所述,所有的序列类型 都是可迭代的。

从代码的角度看,迭代器是实现了迭代器协议方法的对象或类。迭 代器协议方法主要是两个:

  • __iter__();
  • __next__()。

“__iter__()”方法返回对象本身,它是for语句使用迭代器的要求。

“__next__()”方法用于返回容器中下一个元素或数据。当容器中的 数据用尽时,应该引发Stoplteration异常。

任何一个类,只要它实现了或具有这两个方法,就可以称其为迭代 器,也可以说是可迭代的。

自定义迭代器

【实例9-1】自定义一个迭代器的演示实例,其代码如下:

class Mylterator:                           #自定义类迭代器类Mylterator

    def __init__(self,x=2,xmax=100):        #定义构造方法,初始化实例属性  
        self.__mul, self.__x = x,x         
        self.__xmax = xmax

    def __iter__(self):                    #定义迭代器协议方法,返回类自身         
        return self

    def __next__(self):                     #定义迭代器协议方法         
        if self.__x and self.__x != 1:            
            self.__mul *= self.__x            
            if self.__mul <= self.__xmax:
                return self.__mul           #返回值            
            else:               
                raise Stoplteration         #引Stoplteration错误         
        else:            
            raise Stoplteration



if __name__ == '__main__':      
    myiter = Mylterator()                   #实例化迭代器Mylterator      
    for i in myiter:                        #遍历并输出值         
        print ('迭代的数据元素为:',i)

【代码说明】代码中首先定义了迭代器类Mylterator,在其构造方 法中,初始化两个私有的实例属性,用于产生序列和控制序列产生的最大值。该迭代器总是返回所给数的n次方,但其最大值超过xmax参数值 的大小时,就会引发Stoplteration错误,并结束遍历。最后,实例化迭代 器类,并遍历迭代器的值序列,同时进行输出。

从代码中可以看出:如果需要产生很大范围的数的序列,采用列表 或元组等进行一次性生成,则必须会占据大量的内存空间,对系统有很 大的“杀伤力”。而使用了迭代器,则可以每次调用时生成一个,显然可 以节约大量的内存空间。

注:迭代器类一定要在某个条件下引发Stoplteration错误,以结束遍 历循环,否则会产生死循环。

【运行效果】如图所示,初始化迭代器时使用了默认参数,遍 历得到的序列是2的n次方的值,最大值不超过100。

内置迭代器工具

Python语言中,已经内建了一个用于产生迭代器的函数iter(),另外 在标准库的itertools模块中还有丰富的迭代器工具,它们存在于itertools 模块中。

1.內建迭代器函数iter()

内建的iter()函数具有两种使用方式,其原型如下:

  • iter (iterable)
  • iter (callable, sentinel)

第一种原型中只有一个参数,要求参数为可迭代的类型,当然也可 以使用前文所说的各种序列类型。

第二种原型中具有两个参数,第一个参数是可调用类型,一般为函 数;第二个参数称为“哨兵”,即当第一个参数(函数)调用返回值等于 第二个参数的值时,迭代或遍历停止。

2.itertools模块中常用工具函数

itertools模块中提供了近二十个迭代器工具函数,主要有三类,常用的主要有:
无限迭代器:

  • count (start, [step])                         #从start开始,以step为步进行计数迭代
  • cycle (seq)                                     #无限循环迭代
  • seq repeat (elem, [n])                    #循环迭代elem

迭代短序列:

  • chain (p, q, ...)                               #链接迭代(将p,q连接起来迭代,就像从一个
  • compress (data, selectors)           #依据selectors中的值选择迭代data序列中
  • dropwhile (pred, seq)                    #当pred对序列元素处理结果为假时开始迭代s
  • filterfalse (pred, seq)                     #当pred处理为假的元素
  • takewhile (pred, seq)                    #与dropwhile相反
  • tee (it, n)                                       #将it重复n次进行迭代
  • zip_longest (p,q,...)

组合迭代序列

  • product (p, q,...[, n])                     #迭代排列出所有的排列
  • permutations (p, r)                       #迭代序列中r个元素的排列
  • combinations (p, r)                       #迭代序列中r个元素的组合

注:使用无限迭代器时,必须有迭代退出的条件,否则会导致死循环。

生成器

使用生成器,可以生成一个值的序列用于迭代,并且这个值的序列 不是一次生成的,而是使用一个,再生成一个,的确可以使程序节约大量内存。

生成器的创建

生成器对象是通过使用yield关键字定义的函数对象,因此,生成器 也是一个函数。生成器用于生成一个值的序列,以便在迭代中使用。 

【实例9-3】演示了自定义生成器函数及其使用的实例,其代 码如下:

def myYield(n):                     #定义一个生成器(函数)

    while n>0:         
        print ("开始生成...:")         
        yield n                       #yield语句,用于返回给调用者其后表达式的值  
        print ("完成一次...:")         
        n -= 1   
    if __name__ == '__main__':      
        for i in myYield(4):             #for语句遍历生成器         
            print ("遍历得到的值:",i)
        print()   
        my_yield = myYield(3)               #生成一个生成对象   
        print ('已经实例化生成器对象')   
        my_yield.__next__()                 #手工调用其特殊方法,获取序列中一个值   
        print ('第二次调用__next__()方法:')   
        my__yield.__next__()

【代码说明】代码自定义了一个递减数字序列的生成器,每次调用 时都会产生一个从调用时所提供值为初始值的不断递减的数字序列。生 成对象可以直接被for遍历,也可以手工进行遍历,手工的方法见上面代 码最后两行。

【运行效果】如图9.3所示,第一次使用for语句直接遍历自己创建 的生成器,第二次用手工的方法获取生成器产生的数值序列:

深入生成器

如上图所示,程序运行结果中的空行之后的输出“已经实例化生成 器对象”之前,已经实例化了生成器对象,但生成器并没有运行(没有 输出“开始生成”)。当第一次手工调用__next__()方法之后,才输出“开 始生成”,标志着生成器已经运行,而在输出“第二次调用__next__()方 法:”之前并没有输出“完成一次”,说明yield语句运行之后就立即停止 了。而第二次调用__next__()方法之后,才输出“完成一次…”,说明生 成器的恢复运行是从yield语句之后开始运行的。

yield语句不仅可以使函数成为生成器和返回值,还可以接受调用者 传来的数值。但值得注意的是:第一次调用生成器时不能传送给生成器 None以外的值,否则会引发错误。 

生成器与协程

上节所述的运用send()方法来重置生成器的生成序列,其实也称为 协程。协程是一种解决程序并发的方法。

装饰器

装饰器是一种增加函数或类的功能的简单方法,它可以快速地给不 同的函数或类插入相同的功能。从本质上说,它是一种代码实现方式。

装饰器的表示语法是使用一个特殊的符号“@”来实现的。装饰器装 饰函数或类就是用“@装饰器名称”放在函数或类的定义行之前即可。例 如,有一个装饰器名称为disp_run_time,在要使用装饰器的函数定义时 使用如下形式:

@disp_run_time 
def decorated__fun():    
    pass

使用了装饰器后,此处定义的函数decorated_fun()就可以只定义自 己所需的功能,而装饰器所定义的功能会自动插入到函数decorated_fun()之中。这样,可以节约大量具有相同功能的函数或类的 代码。即使是不同目的或不同类的函数或类也可以插入相同的功能。

装饰函数

【实例9-6】演示了自定义一个装饰器并用来装饰自定义的函 数,代码如下:
 

def abc (fun):                    #定义一个装饰器abc      
    def wrapper (*args,**kwargs):  #定义包装器函数         
        print ('开始运行...')         
        fun (*args, **kwargs)       #调用被装饰函数         
        print ('运行结束!')      
    return wrapper                 #返回包装器函数

@abc #装饰函数语句   
def demo_decoration (x):          #定义普通函数,被装饰器装饰      
    a = []      
    for i in range(x):         
    a.append(i)      print (a)

@abc   
def hello (name):                 #定义普通函数(被装饰器装饰)      
    print('Hello',name)

if __name__ == '__main__':      
    demo_decoration(5)             #调用被装饰器装饰的函数      
    print()
    hello ('John')                 #调用被装饰器装饰的函数

【代码说明】代码中首先定义了一个装饰器函数(abc),它带有 一个可以使用函数对象的参数。接着定义了两个被装饰器装饰的普通函 数(demo_decoration、hello)。最后对被装饰的函数进行调用。由此可 以看出,调用被装饰的函数,与调用普通函数没有任何区别。而在装饰 器定义的内部,很明显又定义了一个内嵌的函数wrapper(),在这个内嵌 的函数中执行了其他的一些语句,也调用了被装饰的函数。最后返回了 这个内嵌的函数,代替了被装饰的函数,从而完成了装饰器的功能。

【运行效果】如图所示,达到了在调用两个被装饰的函数前后 输出了相应的信息的功能。

装饰类

装饰器不仅可以装饰函数,也可以装饰类。定义装饰类的装饰器, 采用的方法是:定义内嵌类的函数,并返回新类。 

【实例9-7】演示了一个类装饰器及其使用的例子,代码如下:

def abc(myclass):                     #定义类装饰器      
    class InnerClass:                   #定义内嵌类         
        def __init__(self, z=0):            
            self.z = 0            
            self.wrapper = myclass()      #实例化被装饰的类

        def position (self):            
            self.wrapper.position()            
            print('z axis:',self.z)
    return InnerClass                   #返回新定义的类

@abc #应用装饰器   
class coordination:                    #定义普通的类      
    def __init__(self,x=0,y=0):         
        self.x = x         
        self.y =y
    
    def position (self):         
        print('x axis:',self.x)         
        print('y axis:',self.y)

  if __name__ == '__main__':      
        coor = coordination()               #实例化被装饰的类      
        coor.position()                     #调用方法position()

【代码说明】代码中首先定义了一个能够装饰类的装饰器abc;在其 中定义了一个内嵌类InnerClass用于代替被装饰的类,并返回新的内嵌 类。而在实例化普通类时,得到的就是被装饰器装饰后的类。

【运行效果】如图9.8所示,原来定义的坐标类只包含平面坐标, 而通过装饰器的装饰后,则成为了可以表示立体坐标的三个坐标值。在 图中可以看出显示的坐标为立体坐标值。

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值