zoukankan      html  css  js  c++  java
  • Python函数篇(4)-迭代器与生成器

    1.文件操作的“b模式”(补充)

      在上一篇文章中,我在最后一部分写了文件处理的一些方法,但是觉得还是有必要再提一下如下的内容:

      像rb、wb、ab这种模式,是以字节的形式操作,需要注意以下几个问题:

      1)文件不能保存在内存中,只能保存在硬盘中,以二进制的形式,Python只能将字符串写入文本文件,要将数值数据存储到文本文件中,必须先使用函数str()将其转化为字符串格式。

      2)在以rb .rw等编码打开文件的时候,不能定义编码类型,即不能在open()函数内指定encoding。再补充一些文件操作的方法,具体如下:

    with open("尼古拉斯赵四","wb") as f:
    f.encoding() #文件的打开编码,encoding=“”定义的是哪个编码方式,输出的就是哪个编码方式,与源文件的编码方式无关 #如果不知道源文件编码,可以在定义时将encoding=“latin-1”,该编码方式兼容大部分编码 #f.flush() #刷新,当对文件进行修改操作的时候,通过此方法可以使更改生效(pycharm不需要此方法的原因是pycharm内部机制会自动保存) #f.tell() #打印光标所在的位置,光标移动 是以字节为单位,read()是以字符为单位,中文3个字节,英文一个字节 #with open("尼古拉斯赵四","w",encoding="utf-8",newline="") as f: 读取源文件中真正的换行符,
                                              通过readlines方法读取文件,不加newline=“”的话输出 ,加上是
    #f.seek(0) #指定光标的位置,在0处 # f.seek(10,0) #后面的是默认位置,即光标位置从0开始,以b的方式操作,因为seek是以字节为单位移动光标 # f.seek(10,1) #1代表的相对位置 # f.seek(3,1) #基于10移动光标 # f.seek(-5 ,2) #2代表倒序指定光标位置 # f.truncate(10) #从开头截取到10 (光标位置) ww+模式下不行

    2.文件路径

      如果程序文件存放在当前路径下,那么通过open("文件名称")的方式就可以打开文件,但如果程序文件存放在其他路径下或或当前文件的子目录下,那么就必须要提供文件路径,它让Python到系统中的特定位置去找。

      相对路径

      假如:在当前路径下有一个files文件,files文件下有一个“尼古拉斯赵四”这个程序文件,我如果想要打开这个文件,就需要使用相对文件路径来打开它。

    with open("files尼古拉斯赵四",encoding="utf-8") as f:
        print(f.readlines())

      这行代码让Python去打开文件夹files下的“尼古拉斯赵四”这个文件,在Windows系统中,文件路径使用反斜杠()而不是斜杠(/)

      绝对路径

      可以将文件在计算机中的准确位置告诉Python,这样就不用关心当前运行的程序存储在什么地方,这称为绝对路径。当相对路径行不通时,可以使用绝对路径。绝对路径通常比相对路径更长,在Linux系统中类似于这样:/home/dir/files/1.txt;在Windows系统中类似于这样:C:Usersdirfiles1.txt

      通过使用绝对路径,可读取系统中的任何地方的文件。

    3.迭代器

      迭代器和递归函数的区别:递归函数是不断的重复调用自己,必须有一个明确的条件,而且每进行更深一层的循环,规模一定要较之前要小,迭代器,每次循环都要依赖于上一次的结果。

      迭代器协议:对象必须提供一个_next_()方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常(只能往后走不能往前退)。

      可迭代对象:实现了迭代协议的对象(如何实现?对象内部定义一个_iter_()方法)。

      协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for循环,sum,min,max函数等)使用迭代器协议访问对象。

      以for循环举例:for循环就遵循迭代器协议来循环所有的对象,(列表、字典、字符串、元组,集合)这些其实都不是可迭代对象,只不过在for循环时,调用了他们内部的_iter_方法,把他们变成了可迭代对象,然后for循环调用可迭代对象,然后就可以调用_next_()方法,直至异常结束,用代码解释如下:

    name=[1,2,3]for i in name:         l=name.__iter__()   print(l.__next__())    print(i)

      在for循环列表的时候,实质上是调用了列表的内置方法_iter_(),将列表变成一个可迭代对象,成为可迭代对象后,该列表就有了_next_()方法,在调用此方法一个一个读取。

      还有一个next()方法,其实质就是在调用_next_()函数。

      可以被next()函数调用并不断返回值下一个值的对象就是迭代器:Iterator,列表,字典这些基本数据类型虽然是可迭代对象,但不是迭代器,可以通过_iter_()方法将它们变为迭代器。

    name=[1,2,3]
    print(type(name.__iter__()))           通过_iter_方法将可迭代对象变为迭代器
    运行结果:
    <class 'list_iterator'>

    4.列表生成式和三元运算

      列表生成式怎么说呢,就是一种装逼专用吧,我举一个简单的例子吧,我现在需求是输出从1-9的数字,当然大部分人首先会想到for循环

    name=[]
    for i in range(10):
        name.append(i)
    print(name)
    运行结果:
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]                   

      上面这个例子就不多解释了,认真看过我前面博客的,这是很简单的一个for循环,但如果我就嫌麻烦,这代码太多了,我就要用一行写出来,能不能办到呢?

    print([i for i in range(10)])       
    运行结果:
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]   

      ok,装逼版本,这就是列表表达式。

      那么什么是三元运算呢?

    name="尼古拉斯赵四"
    print("会街舞" if name=="尼古拉斯赵四" else "不会街舞")        一元:“会街舞”  二元:通过if语句判断   三元:“不会街舞”
    输出结果:
    会街舞

      其实很好理解,if前面可以理解为判断为True的返回结果,else后是判断为False的返回结果,这就是三元运算。

      三元运算还可以与列表生成式结合使用,需求:输出10以内大于5的数字

    print([i for i in range(10) if i>5  ])
    运行结果:
    [6, 7, 8, 9]

      但注意一点,在这种语句,就不能在家else了,一定要注意三元,加上了else就变成四元了,程序会报错的

    5.生成器

      在Python中,一边循环一边计算的机制,称为生成器(generator)。生成器可以理解为一种数据类型,这种数据类型自动实现的迭代器协议(其他的数据类型是通过调用自己的内置方法_iter_方法),所以生成器就是可迭代对象,直接就可以使用_next_()方法。

      生成器分类在python中的表现形式(python有两种不同的方式提供生成器)

      1.生成器表达式,生成器其实就是把列表生成器的[]变为()。即上面的列表生成式,我要将它变为生成器的话:

    print(type((i for i in range(10) if i>5  )))
    运行结果:
    <class 'generator'>

      generator保存的是算法,每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

    a=(i for i in range(10) if i>5  )
    print(a.__next__)
    print(next(a))              每次执行一次next()操作,只会读取一个值
    print(next(a))
    运行结果:
    <method-wrapper '__next__' of generator object at 0x000001620ECD7888>
    6
    7

      如果这个生成器有N多个值呢?一直用next()显然是不方便的,所以一般都是用for循环。

      2.函数生成式

      只要在定义函数的时候,把return()变为yield()就可以了,yield()保存上一次读取值的位置,当再次调用时,就从该位置开始调用。普通函数遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

    def func():
        yield 1
        yield 2
    res=func()
    print(res.__next__())
    运行结果:
    1

      执行一次_next_()方法,输出1,程序停留在此位置,当再次执行一次_next_()方法时,会从1的位置开始执行,再输出2,这就是函数生成式。当执行_next_()读取完全部元素后,再次执行程序就会抛出StopIteration异常,处理异常的方法我会在接下来的文章中详细介绍。

  • 相关阅读:
    ini_set /ini_get函数功能-----PHP
    【转】那个什么都懂的家伙
    word 2007为不同页插入不同页眉页脚
    August 26th 2017 Week 34th Saturday
    【2017-11-08】Linux与openCV:opencv版本查看及库文件位置等
    August 25th 2017 Week 34th Friday
    August 24th 2017 Week 34th Thursday
    August 23rd 2017 Week 34th Wednesday
    August 22nd 2017 Week 34th Tuesday
    August 21st 2017 Week 34th Monday
  • 原文地址:https://www.cnblogs.com/Chen-Zhipeng/p/8026376.html
Copyright © 2011-2022 走看看