python 学习笔记2

时间:2021-06-29 19:19:56

本次讲使用一个优化的方法来读取文件内容

def m4(file_name):
    
    with open(file_name,'r+') as f:
        while True:
            line = f.readline()
            if not line:
                return
            
            yield line.strip()



 

for line in m4('c:\\data.txt'):
    print line

数据文件c:\\data.txt内容:
line 1-----------
line 2-----------
line 3-----------
line 4-----------
line 5-----------
line 6-----------
line 7-----------
line 8-----------
line 9-----------
line 10----------

执行脚本后,输出内容如下:

python 学习笔记2

这个方式里面使用了yield来产生一个generator,事实上一个带有yield的函数就是一个generator,它和普通的函数不同,生成一个generator看起来像函数调用,但是不会调用任何函数代码,直到对其调用next(),(在for循环中会自动调用next())才开始执行.虽然执行流程仍按照函数的流程执行,但是每次执行到一个yield语句就会中断并返回一个迭代值,下次执行时从yield的下一个语句继续执行.看起来就好像一个函数在正常执行的过程中被yield中断了数次,每次中断都会返回当前的迭代值。


我们把代码里增加点调试代码就可以看到这个效果

def m4(file_name):
print('start read file:%s' %(file_name))
with open(file_name,'r+') as f:
while True:
line = f.readline()
if not line:
return
print('return:%s' %(line.strip()))
yield line.strip()

执行之后得到的结果如下:

python 学习笔记2

可以看到函数开头的start read file只输出了一次,如果不是用yield方式,必然每次调用都会输出这个提示,如果这个文件非常巨大,使用这种方式占用内存的只是一个常数,因此是最优的方式。

yield 的好处是显而易见的,把一个函数改写为一个 generator 就获得了迭代能力,而且执行流程异常清晰

其实可以使用inspect.isgeneratorfunction来判定一个函数是否是一个特殊的 generator 函数

如果只是导入这个库的单个函数,用下面的方式

from inspect import isgeneratorfunction

isgeneratorfunction这个函数名称实在太长了,我们可以用下面的方式把这个名字重定义

from inspect import isgeneratorfunction as isgt

>>> from inspect import isgeneratorfunction as isgt
>>> isgt(m4)
True
>>>

在这里m4 是一个 generator function,而 m4('c:\\data.txt') 是调用 m4 返回的一个 generator,好比类的定义和类的实例的区别:

>>> import types
>>> isinstance(m4, types.GeneratorType)
False
>>> isinstance(m4('c:\\data.txt'), types.GeneratorType)
True
>>>

m4 是无法迭代的,而m4('c:\\data.txt')是可迭代的:

>>> from collections import Iterable as It
>>> isinstance(m4, It)
False
>>> isinstance(m4('c:\\data.txt'), It)
True
>>>