【问题标题】:python- yield and raise exceptionpython-产生并引发异常
【发布时间】:2018-12-13 15:17:05
【问题描述】:

我正在尝试编写一个产生两个变量并根据条件引发异常的函数。 这是一个最小的例子:

def func():
  var1 = 0
  var2 = 1
  yield var1, var2
  if not var1 > var2:
    raise Exception(var1,var2)
var1, var2 = (1,1)
var1,var2 = func()

此结构目前不产生 var1、var2 并引发异常。 我需要它在这个函数本身内产生和引发异常,以便其他模块可以直接使用这个函数而无需额外的代码。 如果 yield 语句不是一个好主意,那是什么?

尝试过 - [_ for _ in func()] 但 var1 和 var2 的值并没有像预期的那样从产量改变。
尝试过 - var1, var2 = next(func()) 这会产生但不会引发异常。

【问题讨论】:

  • 你提出什么样的Exception?你能创建一个最小的可重现示例吗?
  • 如果你在它之前让步,为什么要检查条件行?这个问题需要使用yield吗?
  • 很抱歉,由于我的初始化和测试用例相同,我理解错误。请检查我将对该问题进行的编辑。
  • 这很奇怪。我曾预计执行会在 yield 之后暂停,这样 raise 就不会被执行,但情况似乎并非如此。

标签: python exception-handling generator


【解决方案1】:

好的,这里先解决几个问题。
1. 解包不适用于单个值,它会尝试耗尽可迭代对象并立即解包所有内容。

def func():
#    ..do something...
    yield 1, 2
    yield 3
    yield 4

a, b = func() #ValueError: too many values to unpack (expected 2)
a, b, c, d = func() #ValueError: not enough values to unpack (expected 4, got 3)
a, b, c = func() #Works
print(a) # (1,2)

2.Yield 在遇到的任何地方停止执行。

def func():
    yield 1, 2
    raise Exception

func_gen = func()
print(func_gen) #<generator object func at 0x000000ACB5A5EBF8>
val1, val2 = next(func_gen) #assigns values
next(func_gen) #raises exception only on next pass

3.必须做出妥协(这应该回答你的问题)

func_gen = func()
print(func_gen) #<generator object func at 0x000000ACB5A5EBF8>
for _ in func_gen:
    res = _
#raises Exception but res = (1, 2)

4.改为建议(请不要使用异常,这确实是 if 条件的工作)

def func():
  var1 = 0
  var2 = 1
  flag = not var1 > var2
  yield var1, var2, flag #just add a flag during yield
  #instead of your exception
#  if not var1 > var2:
#    raise Exception(var1,var2)  
  #stuff
  yield 'something else'
func_gen = func()
print(func_gen) #<generator object func at 0x000000ACB5A5EBF8>
for _ in func_gen:
    res = _
    *values, flag = res
    if flag:
        break
var1,var2 = values #0, 1
  1. 最后但并非最不重要的一点是,确保您确实需要 yield,就目前而言,我怀疑该函数既难以阅读,也可能值得分成更小的模块。我强烈建议再看一遍代码,如果可能的话考虑进一步破解它。

【讨论】:

    【解决方案2】:

    您需要迭代来执行异常。遵循最少的代码确实会引发异常。

    def func(a,b):
        #..do something...
        yield a, b
        if a!=b:
            raise Exception(a,b)
    
    [_ for _ in func(1,2)]
    

    这与No 'print' output when using yield?有关

    特别引用那里的一个答案"Calling a generator function as in testFunc(1) simply creates a generator instance; it does not run the body of the code."

    编辑 下面说明解决方案。这也是来自上面引用的线程。

    def func(a,b):
      #..do something...
      for i in range(10):
        a+=1
        yield a, b
        if a>3:
          raise Exception(a,b)
    
    gen=func(1,2)
    next(gen) # returns (2,2)
    next(gen) # returns (3,2)
    next(gen) # return (4,2)
    next(gen) # returns Exception. As expected 
    

    如果您在编辑中提到next(func()),则每次调用next(func()) 时都会创建新的生成器。相反,如上图所示,先实例化它,然后再调用几次。

    社区 Wiki 作为相关问题,不能在评论中添加。

    【讨论】:

    • 是的,但是如何访问产生的 a 和 b?
    • 从您的解决方案中 a 和 b 的值保持不变。即产量实际上并没有返回变量。我希望收益中的变量以及抛出异常。
    • @SharvariGc 这能解决你想要的吗?它会根据需要引发异常。
    • if not a==b 而不是 if a!=b?
    • @Dinesh 是的,它们是一样的,但我怀疑它是一种风格问题。你应该总是喜欢更简单的表达方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-12
    • 2012-05-29
    • 2016-03-18
    • 2019-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多