Reputation: 721
I am trying to write a function that yields two variables and also raises an exception based on a condition. Here is a minimal example:
def func():
var1 = 0
var2 = 1
yield var1, var2
if not var1 > var2:
raise Exception(var1,var2)
var1, var2 = (1,1)
var1,var2 = func()
This structure currently doesn't yield var1, var2 and raises an exception. I need it to yield and raise an exception within this function itself so that other modules can directly use this function without additional code. If the yield statement is not a good idea then what is?
tried - [_ for _ in func()]
but var1 and var2 value doesn't change as expected from yield.
tried - var1, var2 = next(func())
this yields but doesnt raise an exception.
Upvotes: 2
Views: 8638
Reputation: 1565
You need to iterate to execute the exception. Following minimal code indeed raises exception.
def func(a,b):
#..do something...
yield a, b
if a!=b:
raise Exception(a,b)
[_ for _ in func(1,2)]
This is related to No 'print' output when using yield?
In particular quoting from one answer there "Calling a generator function as in testFunc(1) simply creates a generator instance; it does not run the body of the code."
EDIT Following illustrates the solution. This is also from above quoted thread.
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
If you do next(func())
as you mention in your edit, new generator is created every time you call next(func())
. Instead, as illustrated above, instantiate it first and then call several times.
Community Wiki as related question and cannot add this in comment.
Upvotes: 0
Reputation: 6246
Ok, so couple of issues to resolve here first.
1. Unpacking does not work on individual values, it tries to exhaust the iterable and unpack everything at once.
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 stops the execution wherever encountered.
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.A compromise has to be made (this should answer what you asked)
func_gen = func()
print(func_gen) #<generator object func at 0x000000ACB5A5EBF8>
for _ in func_gen:
res = _
#raises Exception but res = (1, 2)
4.A suggestion instead (please do not use exceptions, it is really a job for if-conditions)
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
Upvotes: 0