Python 中 Perl 的 (<>) 等价物是啥?文件输入没有按预期工作

Posted

技术标签:

【中文标题】Python 中 Perl 的 (<>) 等价物是啥?文件输入没有按预期工作【英文标题】:What is the equivalent of Perl's (<>) in Python? fileinput doesn't work as expectedPython 中 Perl 的 (<>) 等价物是什么?文件输入没有按预期工作 【发布时间】:2011-06-01 02:06:25 【问题描述】:

在 Perl 中使用:

while (<>) 
    # process files given as command line arguments

在 Python 中我发现:

import fileinput
for line in fileinput.input():
    process(line)

但是,当命令行中给出的文件不存在时会发生什么?

python test.py test1.txt test2.txt filenotexist1.txt filenotexist2.txt test3.txt 作为参数给出。

我尝试了各种使用 try: except: nextfile 的方法,但似乎无法使用。

对于上面的命令行,脚本应该为test1-3.txt 运行,但是当找不到文件时,只需要静默转到下一个文件。

Perl 在这方面做得很好。我已经在网上搜索了这个问题,但我在任何地方都找不到这个问题的答案。

【问题讨论】:

"但是在没有找到文件的时候静默转到下一个文件。"?真的吗?为什么?如果文件不存在,为什么不应该整个事情都中断? @S.Lott:想想 grep 等 unix 命令行实用程序。它们对有效参数进行操作,但仅对不存在的文件发出警告,并且警告不会导致整个命令中止,尽管它确实使命令退出并显示错误状态。也就是说,perl 不会对不存在的文件“静默”,它还会发出警告。 @S.Lott 有相当有效的案例,例如阅读一组配置文件并忽略其中一些不存在的情况。 @S.Lott:不存在的文件是否代表致命错误是每个应用程序的问题。一些应用程序应该在不存在的文件上中止;例如,如果配置文件不存在,守护进程可能会选择中止,因为需要配置文件。但是,其他应用程序可能不会;例如,缺少配置文件可能只是意味着应用程序应该使用默认值。知道如何处理这两种情况很有用。 【参考方案1】:
import sys
import os

for f in sys.argv[1:]:
    if os.path.exists(f):
        for line in open(f).readlines():
            process(line)

【讨论】:

谢谢你.. 用最简单的击键还有其他答案吗.. 在 Perl.. 而 () @ihightower 是的。采取我的方法,将其放入模块并导入。您只需要for line in read_lines():。尽管 Python 并不针对具有最少击键的晦涩运算符,因此您不会找到像 Perl 的 &lt;&gt; 这样简洁的东西,但您可以将方法重命名为 rl() 之类的东西以获取 @987654325 @如果你绝对必须的话。 这没有考虑到其他可能的错误,比如文件不可读,文件是目录,文本文件被锁定等。我真的同意 OP 如果fileinput 想要有用,它应该提供对其操作的这方面的控制。【参考方案2】:

类似的东西;

import sys

for f in sys.argv[1:]:
    try:
        data = open(f).readlines()
        process(data)
    except IOError:
        continue

【讨论】:

【参考方案3】:

将@Brian 的答案转换为生成器,并捕获IOError,而不是测试是否存在更 Pythonic,然后在失败时向 stderr 打印警告:

import sys

def read_files(files = None):
  if not files:
    files = sys.argv[1:]
  for file in files:
    try:
      for line in open(file):
        yield line
    except IOError, e:
      print >>sys.stderr, 'Warning:', e

for line in read_files():
  print line,

输出(文件baz不存在):

$ python read_lines.py foo bar baz
line 1 of foo
line 2 of foo
line 1 of bar
line 2 of bar
Warning: [Errno 2] No such file or directory: 'baz'

您可能想花点力气整理错误消息,但这可能不值得。

【讨论】:

但是请注意,捕获IOError 将捕获和忽略的不仅仅是“文件不存在”问题。如果文件存在,但不可读,你永远不会知道。当然,这可能没问题,具体取决于应用程序;但是,如果您想区分不存在的文件和读取现有文件的错误,那么捕获和忽略 IOError 是不可行的。 @Brian 确实,但在这种情况下,我会说这是对“文件不存在”的改进。 无参数。正如我所说,这是一个依赖于应用程序的决定。无论哪种方式,这都应该是一个明确的决定。 做 perl 的工作。不要忽略错误,将它们打印到标准输出。 @Brian OP 旨在在这里模仿 Perl。 Perl 在无法读取文件时不会崩溃,我的解决方案也不会。【参考方案4】:

您可以使用 fileinput 模块解决您的问题,如下所示:

import fileinput

input = fileinput.input()
while True:
    try:
        process(input.next())
    except IOError:
        input.nextfile()
    except StopIteration:
        break

很遗憾,您不能使用 for 循环,因为 IOException 会破坏它。

【讨论】:

为此+1! except 子句还应该在 nextfile() 之前执行类似 except IOError, e: sys.stderr.write("%s: %s: %s\n" % (sys.argv[0], input.filename(), os.strerror(e.errno))) 的操作。 +1 感谢 JooMing,tripleee - 有一个坚持使用文件输入的解决方案很有用(快速轻松地更改我现有的代码)【参考方案5】:

我尝试实施@VGE 的建议,但结果证明我的尝试并不太优雅。对于如何改进这一点的任何建议,我将不胜感激。

import sys, fileinput, errno, os

class nosuchfile:
    def readlines(foo, bar):
        return []
    def close(arg):
        pass

EXITCODE=0

def skip_on_error (filename, mode):
    """Function to pass in as fileinput.input(openhook=...) hook function.
    Instead of give up on the first error, skip the rest of the file and
    continue with the next file in the input list.

    In case of an error from open() an error message is printed to standard
    error and the global variable EXITCODE gets overwritten by a nonzero
    value.
    """
    global EXITCODE
    try:
        return open(filename, mode)
    except IOError, e:
        sys.stderr.write ("%s: %s: %s\n" % (sys.argv[0], filename, os.strerror(e.errno)))
        EXITCODE = 1
        return nosuchfile()

def main ():
    do_stuff(fileinput.input(openhook=skip_on_error))
    return EXITCODE

占位符虚拟文件句柄类nosuchfile 和全局变量EXITCODE 都是非常严重的缺陷。我试图弄清楚如何传递对本地范围的 exitcode 变量的引用,但放弃了。

这也无法处理读取时发生的错误,但大多数错误情况似乎都发生在open

【讨论】:

【参考方案6】:

简单、明确、沉默:

import fileinput
from os.path import exists
import sys

for line in fileinput.input(files=filter(exists, sys.argv[1:])):
    process(line)

【讨论】:

【参考方案7】:

也许您可以使用 openhook 参数来控制不存在的文件。

【讨论】:

以上是关于Python 中 Perl 的 (<>) 等价物是啥?文件输入没有按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

perl 和python 翻译序列

如何从 Python 中读取 Perl 数据结构?

Python 等效于 Perl 的 HTTP::Async->next_response

python和perl基本语法区别

在 perl 中解析表数据的问题

在 perl 中使用 XPath 读取 Mac Plist 布尔值