我正在尝试使用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
感谢您的回复。
答案 0 :(得分: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不会检查这些错误,直到它到达那个语句,在第一种情况下不是。
答案 1 :(得分:3)
在函数中使用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