Python Tutorial: Generators - How to use them and the benefits you receive - YouTube

Channel: Corey Schafer

[0]
hey how's it going everybody in this
[2]
python video we're going to be going
[3]
over
[4]
generators and why you'd want to use
[6]
them and some of the advantages that
[8]
they have
[9]
over lists so in this example i have
[11]
this function up here called
[13]
square numbers and what it does is it
[15]
takes in
[16]
a list of numbers and then we have this
[18]
result variable which is set to
[20]
an empty list and then we loop through
[23]
all the numbers
[24]
and from the list that we passed in and
[26]
we append
[27]
the square of that number to the result
[30]
list
[31]
and then after we're done looping
[32]
through all the numbers then we return
[34]
the result
[35]
and then you can see here i have this by
[37]
numbers variable
[39]
set equal to square numbers i'm passing
[41]
in a list of one two three four
[43]
five and then i just print down or then
[46]
i just print out my numbers down here
[48]
so if i run this code then you can see
[50]
that
[51]
our list of one two three four five that
[53]
was passed in
[54]
our result is 1 4 9 16 25
[58]
so currently our square numbers function
[60]
is returning a list
[62]
now how would we convert this to be a
[65]
generator
[66]
well to do this we won't need this
[69]
result variable anymore so we can take
[71]
that out we don't need the return
[73]
statement and this result dot append we
[76]
can take this out
[77]
and all we have to do is type in this
[80]
yield
[81]
keyword and just yield the square
[84]
number here so this yield keyword is
[87]
what makes it a generator
[88]
now if i save this and run it you can
[91]
see now whenever i print
[93]
my nums i'm no longer getting the list
[96]
if you look at the comment here this is
[97]
what the result used to be
[99]
i'm no longer getting 1 4 9 16
[102]
25 the squares of one through five no
[105]
longer getting that result i'm getting
[107]
this generator object here now the
[110]
reason for this is because
[112]
generators don't hold the entire result
[116]
in memory it yields one result at a time
[120]
so really this is waiting for us to ask
[123]
for the next result
[124]
so it has hasn't actually computed
[126]
anything yet now
[128]
if i printed out next my nums which
[131]
asks for the next result then you can
[134]
see that it's
[135]
one because we passed in our list of one
[137]
two three four five
[138]
and then we're looping through that list
[140]
and so one
[142]
is the first value so it's equal to i
[144]
here and we yielded out
[146]
one times one and it gave us that result
[148]
so now
[149]
if we copy this line here and print out
[153]
next mynums a few times here and run
[156]
that
[157]
then you can see that each time that we
[158]
run next it goes
[160]
and gets the next value that's yielded
[163]
so now we have
[164]
uh 1 squared 2 squared which is 4 3
[167]
squared versus 9
[168]
16 25 and so on now 25
[171]
is the last value from our result so
[174]
what if i was to run
[175]
next one more time well if i do that you
[178]
can see that i got an error here
[180]
and the exception that it threw was stop
[182]
iteration and that means that
[184]
the entire generator has been exhausted
[187]
and stop iteration just means that it's
[189]
out of values
[190]
now instead of getting these values one
[192]
at a time
[194]
we still can use a for loop on these
[198]
generators and this is personally how
[200]
i use generators a lot of the time so
[202]
let me comment out this line
[204]
and then let me uncomment that one and
[206]
save it
[207]
so now we're saying for num and my nums
[210]
which my nums is our generator
[212]
print out num so i'll run that and you
[216]
can see that we get
[217]
all of our values and we don't get the
[219]
stop iteration exception
[221]
because the for loop knows when to stop
[222]
before that happens
[224]
so one immediate advantage over a list
[228]
is that i think that this is much more
[230]
readable here
[231]
rather than having the result set to an
[233]
empty list
[234]
and then appending to that result and
[236]
then returning the result
[237]
this is kind of more readable we're
[239]
saying okay i'm passing in
[241]
these numbers for each number and
[244]
that list of numbers yield the result
[247]
now for those of you more familiar with
[249]
python
[250]
you might have noticed that this entire
[252]
process here
[254]
of these lines of code would have been
[256]
much easier to write
[257]
as a list comprehension so let me
[260]
comment it this out and if you don't
[261]
know what a list comprehension is
[263]
don't worry about it too much i just
[264]
want to show the
[267]
generator example with this as well now
[269]
this is a list comprehension here
[271]
and it's going to do exactly what our
[273]
square numbers function did
[275]
so what we're doing is we're creating a
[277]
list and
[279]
we are taking x times x so the square of
[282]
x
[282]
for x in this list of one two three four
[286]
five so if i save this here and run the
[289]
code
[289]
you can see that i still get the same
[291]
results and i can also
[293]
print out this list up here at the top
[296]
now you can create a generator
[298]
in the same way and it's just as easy as
[301]
taking out these brackets and instead
[304]
putting in
[305]
parentheses so if i take out those
[307]
brackets
[308]
put in parentheses now if i run this
[311]
then you can see that when i printed my
[313]
nums here i tried to print it all at
[315]
once
[316]
i got that generator object and then
[318]
when i ran my for loop
[319]
it looped through all the values and
[322]
gave me that result okay so what if you
[325]
wanted to actually print out
[327]
all of the values from the generator
[330]
well like i said they're not currently
[331]
all held in memory but you can convert
[334]
it to a list and it's just
[336]
as easy as just putting
[339]
list and then wrapping that and then if
[342]
i run that
[343]
you can see that it run it that it
[345]
printed it out just as if it was a list
[347]
now when you convert this generator to a
[349]
list then you do
[351]
lose the advantages that you gained in
[354]
terms of performance and i haven't
[355]
talked about performance yet
[357]
but i have a better example to show
[360]
those advantages
[361]
so a generator is better with
[362]
performance because like i said it's not
[364]
holding all the values in memory
[366]
which isn't a big deal at all whenever
[368]
you have a small list like this
[370]
of one two three four five but say that
[373]
you had
[374]
tens of thousands or even millions of
[377]
items to loop through then having that
[379]
many items in memory will definitely be
[382]
noticeable
[383]
but you don't get that with generators
[385]
so whenever you cast a generator to a
[387]
list like this
[388]
if this generator had a lot of values
[392]
that it needed to convert to that list
[394]
then you lose that performance
[396]
in terms of it would put all of those
[399]
values into memory
[400]
so let me show you a better example here
[403]
of
[404]
this performance difference so i have a
[407]
file here where
[408]
um some of this stuff you don't have to
[410]
worry about like these lines here i'm
[412]
just printing out the memory
[413]
and then these names and majors i'm just
[417]
these are just going to be used to make
[418]
some random values
[420]
so i have two different functions here
[422]
one of these
[423]
is going to make a list and one of these
[426]
is going to be
[426]
a generator and they're both returning
[430]
the same values so within this list
[433]
i have my result here and i'm looping
[435]
through
[436]
a number of people that i'm going to
[438]
pass to this function
[440]
and for each person i'm just going to re
[443]
make a person dictionary give it a
[446]
an id and a name that's randomly chosen
[449]
from the list of names up at top
[451]
and a major that's randomly chosen from
[453]
the list of majors
[455]
and then i'm going to return that result
[458]
and for the generator it's the exact
[460]
same thing i'm going to
[462]
loop through the number of people that i
[465]
pass in
[466]
and then i'm going to yield this person
[469]
dictionary
[470]
that has the same values as the list
[473]
function had
[474]
now really quick just to make these the
[476]
same i'm going to make that an
[478]
x range instead so that these are
[479]
exactly the same
[481]
okay so right here don't worry about
[483]
these lines here this
[485]
time dot clock and this t2 time dot
[487]
clock
[488]
all i'm going to do is time how long it
[490]
takes to run
[492]
this function which returns a list now
[494]
i'm going to pass
[495]
in 1 million values to this function
[498]
so it should return a list of 1 million
[502]
results
[503]
and then down here at the bottom i'm
[504]
printing out the memory usage and the
[506]
total time that it took
[507]
so if i run this then you can see
[511]
up here at the top of the code so this
[514]
before here
[515]
this is before i made anything
[519]
so my base memory usage was around 15
[521]
megabytes
[523]
and this memory after is after i created
[525]
that
[526]
list of 1 million records so you can see
[529]
here that it jumped up by
[531]
nearly 300 megabytes and it took
[534]
um 1.2 seconds
[537]
now if you're dealing with large amounts
[538]
of data you know that's not
[540]
out of the ordinary to have one million
[542]
records like that
[544]
so let's see what this looks like if i
[546]
instead use the
[547]
generator example so i'm going to going
[549]
to comment out
[550]
the uh the function that returned the
[553]
list
[554]
and now i'm going to uncomment this
[557]
function that returns a generator
[559]
and i'm going to pass in the same number
[562]
of values i'm going to pass in 1 million
[564]
values here
[565]
so if i save that and run it now you can
[568]
see here after i ran this that the
[569]
memory is almost exactly the same
[572]
and that's because the generator hasn't
[574]
actually
[575]
done anything yet it's not holding those
[577]
million values
[578]
in memory it's waiting for me to grab
[581]
the next one or to loop through those
[583]
and it would give me those one at a time
[585]
now this time that it took here
[587]
basically it didn't take any time
[589]
because as soon as it gets to the first
[591]
yield statement it stops
[593]
so if i was instead to make this an
[596]
integer then it would be
[598]
nearly zero seconds now whenever i said
[600]
earlier that if you convert this to a
[602]
list
[602]
then you lose that performance then
[606]
let me show you what i mean here so i
[607]
will convert this result this entire
[610]
result to a list
[612]
and now if i run this
[615]
then you can see basically i got pretty
[617]
much the same
[618]
result that i got when i ran the
[620]
function that returned the list
[622]
so if i take these back off and just do
[625]
the generator
[626]
then you can see that we get our
[628]
performance back
[629]
so that's how you use a generator you
[631]
know i think that
[633]
it is a little bit more readable and it
[636]
also gives you
[637]
big performance boosts not only with
[640]
execution time but with memory as well
[642]
and you can still use all of the
[645]
comprehensions and this generator
[648]
expression here so you don't lose
[650]
anything
[650]
in that area so those are a few reasons
[653]
why you would use generators and also
[655]
some of the advantages that come along
[657]
with that so i hope this video was
[659]
useful for you guys if you do have any
[661]
questions about this stuff just
[663]
ask in the comment section below be sure
[665]
to subscribe for future python videos
[667]
and thank you guys for watching