繁体   English   中英

Python生成器:错误仅在注释后可见

[英]Python generators: Errors visible only after commenting

我正在尝试遵循python代码来模拟* nix系统的“ tail”命令。

import sys
def tail(f):
    print 'in tail with ',f
    f.seek(0,2)
    while True:
        line = f.readline()
        if not line:
            time.sleep(0.1)
            continue
        yield line

if(len(sys.argv) >= 2):
    print 'calling tail'
    tail(open(sys.argv[1],'r'))
else:
    print 'Give file path.\n'

我犯了一个错误(缺少导入时间模块)。 但是,奇怪的是没有错误被抛出并且程序正在悄悄地退出。 输出(评论前):

$ python tail.py /var/log/dmesg 
calling tail

但是,如果我在使用时间模块的注释行之后注释行,则会引发错误。

import sys
def tail(f):
    print 'in tail with ',f
    f.seek(0,2)
    while True:
        line = f.readline()
        if not line:
            time.sleep(0.1)
        #     continue
        # yield line

if(len(sys.argv) >= 2):
    print 'calling tail'
    tail(open(sys.argv[1],'r'))
else:
    print 'Give file path.\n'

输出(评论后)

$ python tail.py /var/log/dmesg 
calling tail
in tail with  <open file '/var/log/dmesg', mode 'r' at 0x7fc8fcf1e5d0>
Traceback (most recent call last):
  File "tail.py", line 14, in <module>
    tail(open(sys.argv[1],'r'))
  File "tail.py", line 8, in tail
    time.sleep(0.1)
NameError: global name 'time' is not defined

任何人都可以解释为什么在第一种情况下未引发错误(在评论之前)吗? 解释器上线后,是否应该立即抛出错误?

更正的程序:

import sys
import time
def tail(f):
    print 'in tail with ',f
    f.seek(0,2)
    while True:
        line = f.readline()
        if not line:
            time.sleep(0.1)
            continue
        yield line

if(len(sys.argv) >= 2):
    print 'calling tail'
    t = tail(open(sys.argv[1],'r'))
    for i in t:
        print i
else:
    print 'Give file path.\n'

输出:

$ python tail.py hello.txt 
calling tail
in tail with  <open file 'hello.txt', mode 'r' at 0x7fac576b95d0>
hello there 1

hello there 2

hello there 3

感谢您的答复。

简短答案

第一个是实例化生成器(但不将其分配给变量),第二个是函数调用。


长答案

这是由于python的动态类型检查,当您具有yield语句时,您的函数就相当于生成器,并且此行-

tail(open(sys.argv[1],'r'))

表示您正在实例化生成器而不调用函数 当您将此实例分配给某个变量并为生成器调用next 实际触发它的方法时,就会得到该错误,即-

t = tail(open(sys.argv[1],'r')) # t is a generator here 
t.next()

在另一种删除yield语句的情况下,它开始表现为正常功能,这意味着tail(open(sys.argv[1],'r'))现在是函数调用,因此引发错误。

我所说的动态是python在到达该语句之前不会检查这些类型的错误,在第一种情况下不是这样。

在函数yield中,它是一个生成器。 生成器函数仅在请求下一个值时才执行其包含的代码。 简单地调用生成器函数只会创建该生成器对象。 如果您不对该对象执行任何操作(例如遍历对象),则不会发生任何事情。

删除yield使函数急切地求值,因此实际上执行其代码。

如果您实际上遍历了生成器,则当/当readline()生成空行时,它将生成一个错误。 由于这样的空行只能出现在文件的末尾(看起来像空行实际上包含单个换行符),因此将其置于循环中毫无意义。 代替这个:

while True:
    line = f.readline()
    if not line:
        time.sleep(0.1)
        continue
    yield line

用这个:

for line in f:
    yield line

而不是这样:

if(len(sys.argv) >= 2):
    print 'calling tail'
    tail(open(sys.argv[1],'r'))

您实际上应该执行生成器的内容,如下所示:

if(len(sys.argv) >= 2):
    print 'calling tail'
    for line in tail(open(sys.argv[1],'r')):
        print line

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM