【问题标题】:Return with argument inside generator在生成器内返回参数
【发布时间】:2016-07-29 15:38:43
【问题描述】:

我知道已经有人问过类似的问题,但没有回答我的需要,因为我的有点不同。

我的代码:

def tFileRead(fileName, JSON=False):
    with open(fileName) as f:
        if JSON:
            return json.load(f)
        for line in f:
            yield line.rstrip('\n')

我想做什么: 如果JSON 为真,则表示它是从json 文件中读取的,我想返回json.load(f),否则,我想将文件的行生成到生成器中。

我尝试了将生成器转换为 json 的替代方法,但它变得非常混乱、非常快,而且效果不佳。

【问题讨论】:

  • 如果不是 JSON,请尝试返回一个作为生成器的闭包
  • 单个函数必须返回或屈服。不是两者都
  • 你可以yield from json.load,但这只会产生字典中的键。您打算如何在这两种情况下使用该功能?
  • 你试图让这个函数做太多事情......调用者已经知道它是否是 JSON,所以让它调用一个返回 json 的函数或调用一个函数并不是不合理的产生行 - 两者完全不同,调用者必须知道如何处理每行的结果......
  • @Islarf 你应该有两个功能 - 一个用于 json 和一个用于行读取。调用者知道它是否是 json,因此它应该负责调用适当的函数,这样它也知道这样做会得到哪种输出。让函数太聪明或做太多只会给他们和调用者带来麻烦。

标签: python json generator readfile


【解决方案1】:

我想到的第一个解决方案是显式返回一个生成器对象,该对象将提供您尝试实现的确切行为。

问题是:如果你明确地返回了一个像 return (line.rstrip('\n') for line in f) 这样的生成器对象,文件将在返回后关闭,并且从文件中进一步读取将引发异常。

您应该在这里编写两个函数:一个读取 json 文件,一个读取普通文件。然后,您可以编写一个包装器,该包装器基于要调用这两个函数中的哪一个的参数。

或者只是将迭代部分移动到另一个函数中,如下所示:

def iterate_file(file_name):
    with open(file_name) as fin:
        for line in fin:
            yield line.rstrip("\n")


def file_read(file_name, as_json=False):
    if as_json:
        with open(file_name) as fin:
            return json.load(fin)
    else:
        return iterate_file(file_name)

【讨论】:

  • 你为什么要谈论他们没有做的事情的问题?
  • @StefanPochmann 你是对的。我在这里错过了一步。我在想你可以那样做......但是等等,不,那是行不通的。这就是我提到它的原因。
【解决方案2】:

您可以 yield from 加载 JSON 的字典,从而遍历字典中的键值对,但这不是您想要的行为。

def tFileRead(fileName, JSON=False):
    with open(fileName) as f:
        if JSON:
            yield from json.load(f).items()  # works, but differently
        for line in f:
            yield line.rstrip('\n')

如果你可以只返回一个生成器会很好,但这不会起作用,因为使用with,文件会在函数返回后立即关闭,即在生成器被消耗之前。

def tFileRead(fileName, JSON=False):
    with open(fileName) as f:
        if JSON:
            return json.load(f)
        else:
            return (line.rstrip('\n') for line in f)  # won't work

或者,您可以定义另一个函数,仅用于从文件中产生行并在生成器中使用它:

def tFileRead(fileName, JSON=False):
    if JSON:
        with open(fileName) as f:
            return json.load(f)
    else:
        def withopen(fileName):
            with open(fileName) as f:
                yield from f
        return (line.rstrip('\n') for line in withopen(fileName))

但是一旦你在那里,你真的可以只使用两个单独的函数来读取文件 en-block 作为 JSON 或迭代行......

【讨论】:

  • 你怎么知道 JSON 加载到一个字典,而不是一个列表?另外,我发现 “如果你可以只返回一个生成器” 具有误导性,因为你正在返回一个生成器(在你的第一个版本中)。
  • @StefanPochmann 关于字典:你是对的,没有考虑 JSON 返回例如一个列表。关于返回生成器:我的意思是返回 return,就像在第二种方法中一样。
猜你喜欢
  • 2020-11-02
  • 2021-04-07
  • 1970-01-01
  • 1970-01-01
  • 2021-10-15
  • 2017-12-29
  • 2021-06-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多