When should I use return yield and when should I use return only?
Yield is a keyword in Python that is used to return from a function without destroying the states of its local variable and when the function is called, the execution starts from the last yield statement. Any function that contains a yield keyword is termed a generator. Hence, yield is what makes a generator.
Yield is generally used to convert a regular Python function into a generator. Return is generally used for the end of the execution and “returns” the result to the caller statement. It replace the return of a function to suspend its execution without destroying local variables.
A return in a function is the end of the function execution, and a single value is given back to the caller. When the function is called and it encounters the yield keyword, the function execution stops. It returns generator object back to the caller.
In computer science, yield is an action that occurs in a computer program during multithreading, of forcing a processor to relinquish control of the current running thread, and sending it to the end of the running queue, of the same scheduling priority.
Use yield when you are returning an enumerable, and you don't have all the results at that point.
Practically, I've used yield when I want to iterate through a large block of information (database, flat file, etc.), and I don't want to load everything in memory first. Yield is a nice way to iterate through the block without loading everything at once.
The yield
keyword is incredibly powerful. It basically allows you to quickly return IEnumerable
and IEnumerator
objects without explicitly coding them.
Consider a scenario where you want to return the intersection of two IEnumerable objects. Here is how you would do it using the yield keyword.
public static class Program { public static void Main() { IEnumerable<object> lhs = new List<int> { 1, 2, 3, 4, 5 }; IEnumerable<object> rhs = new List<int> { 3, 4, 5, 6, 7 }; foreach (object item in IntersectExample.Intersect(lhs, rhs)) { Console.WriteLine(item); break; } } } public static class IntersectExample { public static IEnumerable<object> Intersect(IEnumerable<object> lhs, IEnumerable<object> rhs) { var hashset = new HashSet<object>(); foreach (object item in lhs) { if (!hashset.Contains(item)) { hashset.Add(item); } } foreach (object item in rhs) { if (hashset.Contains(item)) { yield return item; } } } }
It is hard to appreciate this until you fully realize what is going on. Normally when you intersect two sets you complete the entire operation before returning the result to the caller. The means the runtime complexity of the operation is O(m + n)
, where m
and n
are the sizes of the collections being intersected, regardless of what you do with the result afterwards. But, in my example I just wanted to pick off the first item from the result. Using an IEnumerable
that was created by the yield
keyword makes it super easy to delay part of the processing until it is actually required. My example runs in O(m)
. The alternative is to code the IEnumerable
and maintain the state in it manually. The power of the yield
keyword is that it creates that state machine for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With