【问题标题】:Why can't I use yield with return?为什么我不能将收益与回报一起使用?
【发布时间】:2013-08-15 11:12:11
【问题描述】:

我希望您考虑以下代码:

def func(alist):
    if len(alist) == 1:
        return arg * 2
    for item in alist:
        yield item * 2

当我运行它时,我得到这个错误:

SyntaxError: 'return' with argument inside generator

现在,我意识到我无法做到这一点。但是,我想知道为什么。导致 Python 抛出 SyntaxError 的幕后究竟发生了什么?

【问题讨论】:

  • 我很好奇为什么你有时会想要让步,有时又想要返回。您将如何正确使用这样的功能?你不需要事先检查你传递的列表的长度,以确保你调用它的方式正确吗?
  • 总是yield 结果几乎肯定比您尝试的更好。
  • 因为我最初并没有真正看到只为 1 个项目创建生成器的理由。但是,我有点得出结论,那就是我应该做的。就像我之前说的,我的问题的重点是“为什么我不能?”不是“我应该吗?”。我很好奇 Python 在内部是如何工作的,以及为什么它不会让它工作。
  • 从 Python 3.3 开始可以。见python.org/dev/peps/pep-0380

标签: python function return python-2.x yield


【解决方案1】:

请看这里:What does the "yield" keyword do in Python?

这将详细描述您的问题。 简而言之,因为 Python 将解释函数的方式(作为生成对象或返回对象,Python 中的一切都是对象,有些东西会将那个对象定义为特定类型。在这种情况下,Yield 是生成对象)

TL;DR:您不能在同一函数中使用 yieldreturn。在函数中尽可能多地使用其中之一,而不是同时使用两者。

【讨论】:

    【解决方案2】:

    不是这样,你不能使用 return 和 yield,而是你不能使用 return 和参数,当你的函数有一个 yield 使它成为一个生成器时

    您可能希望将实现更改为

    def func(lis):
        for item in lis:
            yield item * 2
    

    【讨论】:

    • 也可以完全删除if 并执行def func(lis): for item in lis: yield item * 2
    【解决方案3】:

    你想要的确实是可能的:

    def func(lis):
        if len(lis) == 1:
            return lis[0] * 2
        else:
            return (item * 2 for item in lis)
    

    这在一种情况下返回一个值,在另一种情况下返回一个生成器。

    但请注意,这会导致问题:每次通话时,您都必须做出区分

    res = func(lis)
    if len(lis) == 1:
        print res # my value
    else:
        for i in res: print i # several values
    

    最好将这两个用例区分开来:

    1. 你可以的

      def func(val):
          return val * 2
      

      并且,当你需要时,做任何一个

      reslist = [func(i) for i in lis]
      resgen = (func(i) for i in lis)
      

    2. 你可以的

      def func(lis):
          for item in lis:
              yield lis[0] * 2
      
      def func1(val):
          for i in func([val]):
              return i # returns the first value
      

    【讨论】:

      【解决方案4】:

      Python 必须在字节码编译时决定一个函数是否是生成器。这是因为生成器的语义表明生成器函数中的任何代码都不会在第一次 next 调用之前运行;生成器函数返回一个生成器迭代器,当调用next 时,它运行生成器代码。因此,Python 无法通过运行一个函数来决定它是否应该是一个生成器,直到它遇到yieldreturn;相反,yield 在函数中的存在表明该函数是一个生成器。

      【讨论】:

      • 我接受您的回答,因为您回答了我想要的:“为什么不能这样做?”。其他答案更侧重于寻找解决方法(这很好,但不是我想要的)。谢谢。
      【解决方案5】:

      其他答案已经解释了产量/退货问题。您可以使用map 来简化此操作:

      def func(lis):
          return map(lambda item: item * 2, lis)
         # similar to: return [item * 2 for item in lis]
      

      当然,这总是会返回一个列表,因为lis 是一个列表,即使它只有一个项目。您可以将其更改为复合语句:

      def func(lis):
          return map(lambda item: item * 2, lis) if len(lis) > 1 else lis[0] * 2
      

      【讨论】:

        猜你喜欢
        • 2017-05-30
        • 2012-09-16
        • 2016-12-21
        • 1970-01-01
        • 2018-01-23
        • 2010-12-01
        • 1970-01-01
        • 2020-08-26
        • 2013-07-02
        相关资源
        最近更新 更多