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

Python生成器:仅在注释后可见的错误,python,error-handling,generator,Python,Error Handling,Generator,我试图按照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)

我试图按照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
输出:

$ 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'))
表示您正在实例化生成器,而不是调用函数。当您将此实例分配给某个变量并调用生成器的下一个方法时,您将得到该错误,该方法实际上会触发它,即-

t = tail(open(sys.argv[1],'r')) # t is a generator here 
t.next()
在另一种情况下,您删除了yield语句,它开始作为一个普通函数运行,这意味着-tailopensys.argv[1],'r'现在是一个函数调用,因此它抛出了一个错误

我所说的动态是指python在到达该语句之前不会检查此类错误,而在第一种情况下,它不会检查此类错误。

简短回答

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

长话短说

这是因为python的动态类型检查,当您有yield语句时,您的函数表现为生成器,这一行-

tail(open(sys.argv[1],'r'))
表示您正在实例化生成器,而不是调用函数。当您将此实例分配给某个变量并调用生成器的下一个方法时,您将得到该错误,该方法实际上会触发它,即-

t = tail(open(sys.argv[1],'r')) # t is a generator here 
t.next()
在另一种情况下,您删除了yield语句,它开始作为一个普通函数运行,这意味着-tailopensys.argv[1],'r'现在是一个函数调用,因此它抛出了一个错误

我所说的动态是,python在到达该语句之前不会检查此类错误,而在第一种情况下,它不是。函数中有yield,它是一个生成器。生成器函数仅在请求下一个值时执行其包含的代码。简单地调用生成器函数只会创建生成器对象。如果您这样做时没有对该对象执行任何操作,例如在其中循环,则不会发生任何事情

删除yield会使函数急切地求值,因此它的代码实际上是被执行的

如果您确实在生成器上进行了迭代,那么如果/当readline生成空行时,它将生成一个错误。由于这样的空行只能出现在文件的末尾,看起来像空行,实际上包含一个换行符,因此将其放入循环中是没有意义的。与此相反:

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'))
使用以下命令:

for line in f:
    yield line
而不是这个:

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'))
您应该实际执行生成器的内容,如下所示:

if(len(sys.argv) >= 2):
    print 'calling tail'
    for line in tail(open(sys.argv[1],'r')):
        print line
函数中有收益,它是一个生成器。生成器函数仅在请求下一个值时执行其包含的代码。简单地调用生成器函数只会创建生成器对象。如果您这样做时没有对该对象执行任何操作,例如在其中循环,则不会发生任何事情

删除yield会使函数急切地求值,因此它的代码实际上是被执行的

如果您确实在生成器上进行了迭代,那么如果/当readline生成空行时,它将生成一个错误。由于这样的空行只能出现在文件的末尾,看起来像空行,实际上包含一个换行符,因此将其放入循环中是没有意义的。与此相反:

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'))
使用以下命令:

for line in f:
    yield line
而不是这个:

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'))
您应该实际执行生成器的内容,如下所示:

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

在第二次通话中,如果条件只有在您不让行的情况下才能得到满足吗?如果条件只有在您不让行的情况下才能在第二次通话中得到满足吗?谢谢您的回复。延迟和循环用于等待输入,因此其行为类似于linux上的tail命令,如“tail-f hello.txt”。请查看我在原始帖子中的编辑和输出。我同时在另一个终端向文件hello.txt添加文本。谢谢回复。延迟和循环用于等待输入,因此其行为类似于linux上的tail命令,如“tail-f hello.txt”。请查看我在原始帖子中的编辑和输出。我同时在另一个终端向hello.txt文件添加文本。