Signup/Sign In
Ask Question
Not satisfied by the Answer? Still looking for a better solution?

What does the “yield” keyword do?

What is the use of the yield keyword in Python? What does it do?

For example, I'm trying to understand this code1:
def _get_child_candidates(self, distance, min_dist, max_dist):
if self._leftchild and distance - max_dist < self._median:
yield self._leftchild
if self._rightchild and distance + max_dist >= self._median:
yield self._rightchild


And this is the caller:
result, candidates = [], [self]
while candidates:
node = candidates.pop()
distance = node._get_dist(obj)
if distance <= max_dist and distance >= min_dist:
result.extend(node._values)
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result


What happens when the method _get_child_candidates is called? Is a list returned? A single element? Is it called again? When will subsequent calls stop?
by

2 Answers

akshay1995
An iterator is just a fancy sounding term for an object that has a next() method. So a yield-ed function ends up being something like this:

Original version:

def some_function():
for i in xrange(4):
yield i

for i in some_function():
print i

This is basically what the Python interpreter does with the above code:

class it:
def __init__(self):
# Start at -1 so that we get 0 when we add 1 below.
self.count = -1

# The __iter__ method will be called once by the 'for' loop.
# The rest of the magic happens on the object returned by this method.
# In this case it is the object itself.
def __iter__(self):
return self

# The next method will be called repeatedly by the 'for' loop
# until it raises StopIteration.
def next(self):
self.count += 1
if self.count < 4:
return self.count
else:
# A StopIteration exception is raised
# to signal that the iterator is done.
# This is caught implicitly by the 'for' loop.
raise StopIteration

def some_func():
return it()

for i in some_func():
print i

For more insight as to what's happening behind the scenes, the for loop can be rewritten to this:

iterator = some_func()
try:
while 1:
print iterator.next()
except StopIteration:
pass

Does that make more sense or just confuse you more? :)

I should note that this is an oversimplification for illustrative purposes. :)
RoliMishra
yield is just like return - it returns whatever you tell it to (as a generator). The difference is that the next time you call the generator, execution starts from the last call to the yield statement. Unlike return, the stack frame is not cleaned up when a yield occurs, however, control is transferred back to the caller, so its state will resume the next time the function is called.

In the case of your code, the function get_child_candidates is acting like an iterator so that when you extend your list, it adds one element at a time to the new list.

list.extend calls an iterator until it's exhausted. In the case of the code sample you posted, it would be much clearer to just return a tuple and append that to the list.

Login / Signup to Answer the Question.