1
00:00:00,000 --> 00:00:04,990
A generator function is a function that returns an iterator object.

2
00:00:05,000 --> 00:00:10,990
So this is how you create functionality that can be used in a for loop or any

3
00:00:11,000 --> 00:00:13,990
place an iterator is allowable in Python.

4
00:00:14,000 --> 00:00:15,990
So let's go ahead and create a generator object.

5
00:00:16,000 --> 00:00:26,990
We will make a working copy of generator.py, and we'll go ahead and open that up.

6
00:00:27,000 --> 00:00:30,990
And here we have an example of using the range object.

7
00:00:31,000 --> 00:00:34,990
And if we run this, you'll notice that we get our range of numbers up to and

8
00:00:35,000 --> 00:00:42,990
not including the 25, because the range object is naturally noninclusive.

9
00:00:43,000 --> 00:00:46,990
So a lot of times you might want an inclusive range object.

10
00:00:47,000 --> 00:00:48,990
So let's go ahead and create one.

11
00:00:49,000 --> 00:00:55,990
We'll call this inclusive_range, and we'll define a function.

12
00:00:56,000 --> 00:00:59,990
Call it inclusive_range.

13
00:01:00,000 --> 00:01:02,990
And the range object takes three arguments:

14
00:01:03,000 --> 00:01:07,990
start, stop, and step.

15
00:01:08,000 --> 00:01:17,990
And we'll go ahead and say i=start, while i<=stop, and that will make

16
00:01:18,000 --> 00:01:22,990
it inclusive. i+=step.

17
00:01:23,000 --> 00:01:30,990
And then just before we increment, we're going to return, although we're not

18
00:01:31,000 --> 00:01:35,990
going to use return. We're going to yield i.

19
00:01:36,000 --> 00:01:40,990
What that does is it returns I, but because we're using yield instead of

20
00:01:41,000 --> 00:01:45,990
return, the next time the function is called execution will continue right

21
00:01:46,000 --> 00:01:47,990
after the yield statement.

22
00:01:48,000 --> 00:01:53,990
So the next thing that will happen is i will get incremented by step and then

23
00:01:54,000 --> 00:01:55,990
the loop will be tested again.

24
00:01:56,000 --> 00:02:00,990
And then assuming that the loop condition is still true, yield will be called

25
00:02:01,000 --> 00:02:05,990
again and it will yield another iteration in the sequence.

26
00:02:06,000 --> 00:02:10,990
So again, what makes the yield different than return is that as the function

27
00:02:11,000 --> 00:02:15,990
gets called over and over again, each time execution begins right after the

28
00:02:16,000 --> 00:02:20,990
yield and continues as if the function were running continually.

29
00:02:21,000 --> 00:02:25,990
And yield returns each time the next item in the sequence.

30
00:02:26,000 --> 00:02:28,990
So let's go ahead and run this.

31
00:02:29,000 --> 00:02:31,990
In order to run it, we are going to need to give it a start and a step.

32
00:02:32,000 --> 00:02:39,990
So we'll start at 0, and we'll step by 1, and we should get the same sequence,

33
00:02:40,000 --> 00:02:41,990
but including a 25 at the end.

34
00:02:42,000 --> 00:02:48,990
Save it and run it, and there we are, got the same sequence, and there is our 25 at the end.

35
00:02:49,000 --> 00:02:54,990
So that is how yield works and that is how you create a generator.

36
00:02:55,000 --> 00:02:58,990
Let's go ahead and exercise all the techniques we've been learning in this

37
00:02:59,000 --> 00:03:04,990
function chapter and make this function work exactly like range does.

38
00:03:05,000 --> 00:03:08,990
Range can be called with one, two, or three arguments.

39
00:03:09,000 --> 00:03:13,990
If it's called with just one argument, stop is the value that's used and start

40
00:03:14,000 --> 00:03:18,990
is given a default value of 0 and step is given a default value of 1.

41
00:03:19,000 --> 00:03:21,990
But Python doesn't really have a way to do that.

42
00:03:22,000 --> 00:03:27,990
If I give this one here a default value of 0, I say start=0, and I give step a

43
00:03:28,000 --> 00:03:34,990
default value of 1, and I call this with just the 25 by itself.

44
00:03:35,000 --> 00:03:36,990
Save that and run it.

45
00:03:37,000 --> 00:03:37,990
We get this SyntaxError.

46
00:03:38,000 --> 00:03:42,990
Non-default argument follows default argument.

47
00:03:43,000 --> 00:03:45,990
So this is not allowable in Python.

48
00:03:46,000 --> 00:03:49,990
The only way we can really do this is with a tuple.

49
00:03:50,000 --> 00:03:52,990
So let's go ahead and process our arguments.

50
00:03:53,000 --> 00:03:56,990
Let's start by taking a number of arguments, because we are going to different

51
00:03:57,000 --> 00:03:57,990
things with different numbers of arguments.

52
00:03:58,000 --> 00:04:16,990
numargs = the length of tuple, and if numargs<1, we're going to raise an error.

53
00:04:17,000 --> 00:04:20,990
Requires at least one argument.

54
00:04:21,000 --> 00:04:33,990
And then elif numargs == 1, and we'll just set these up, elif numargs == 2,

55
00:04:34,000 --> 00:04:51,990
elif numargs == 3, or else, and we'll raise another error. TypeError, inclusive_range

56
00:04:52,000 --> 00:05:05,990
expected at most 3 arguments, got some number, format (numargs)).

57
00:05:06,000 --> 00:05:11,990
Now I've got this little x here because it's expecting something to be in that suite.

58
00:05:12,000 --> 00:05:17,990
So if there's just one argument, then start is going to be 0 and step is going

59
00:05:18,000 --> 00:05:22,990
to be 1, and we'll go up to the top of the list, and we'll use our argument.

60
00:05:23,000 --> 00:05:29,990
We'll say stop=args0. All right.

61
00:05:30,000 --> 00:05:34,990
And if we have two arguments, then our arguments are start and stop, and we can

62
00:05:35,000 --> 00:05:40,990
assign those like this and give step the default value.

63
00:05:41,000 --> 00:05:44,990
If we have three arguments, and we can assign them all like this.

64
00:05:45,000 --> 00:05:50,990
start, stop, and step=args. All right.

65
00:05:51,000 --> 00:05:52,990
Now, this should work.

66
00:05:53,000 --> 00:05:59,990
Let's save it and see how we are calling it up here? With just the 25 by itself.

67
00:06:00,000 --> 00:06:04,990
So we'll run it, and there we have all 25 numbers, just like we expected.

68
00:06:05,000 --> 00:06:09,990
It works just like range, except it's inclusive and it gives us that last number.

69
00:06:10,000 --> 00:06:16,990
If we have a 5 at the beginning of it, it should give us 5 through 25, there we go.

70
00:06:17,000 --> 00:06:22,990
And if we step by three, let's say, save that and run it.

71
00:06:23,000 --> 00:06:25,990
That's exactly what we expect.

72
00:06:26,000 --> 00:06:29,990
Let's say we have too many arguments. Let's give it some other number.

73
00:06:30,000 --> 00:06:34,990
Now we're going to expect to get this one here.

74
00:06:35,000 --> 00:06:36,990
It's not less than 1. It's not 1.

75
00:06:37,000 --> 00:06:37,990
It's not 2. It's not 3.

76
00:06:38,000 --> 00:06:39,990
It's this something else.

77
00:06:40,000 --> 00:06:41,990
So save that and run it.

78
00:06:42,000 --> 00:06:47,990
And we get inclusive_range expected at most 3 arguments, and got 4.

79
00:06:48,000 --> 00:06:55,990
And let's trigger this error here and give it no arguments at all. Save that and run it.

80
00:06:56,000 --> 00:07:00,990
And requires at least one argument is our error message.

81
00:07:01,000 --> 00:07:03,990
So there we have it. We've duplicated the functionality of the range object.

82
00:07:04,000 --> 00:07:08,990
We've got a function that returns an iterator object and it does exactly what

83
00:07:09,000 --> 00:07:11,990
range does, except that it's inclusive.

84
00:07:12,000 --> 00:07:18,990
And we've accomplished this using the yield statement, which turns our

85
00:07:19,000 --> 00:07:24,990
function into a generator, and the way the yield works is each time yield is run,

86
00:07:25,000 --> 00:07:26,990
it returns the value.

87
00:07:27,000 --> 00:07:32,990
And the next time the function is called, execution picks up from right after the yield.

88
00:07:33,000 --> 00:07:37,990
And this turns the function into a generator and what it generates is an

89
00:07:38,000 --> 00:07:48,000
iterator object, which can be used exactly like any iterator object in Python.

