[220] iterators / generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x)...

43
[220] Iterators / Generators Meena Syamkumar Mike Doescher

Upload: others

Post on 10-Aug-2020

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

[220] Iterators / GeneratorsMeena Syamkumar

Mike Doescher

Page 2: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

Iterators/Generators (Part 2)

Outline• when normal functions aren't good enough• yield keyword by example• the scary vocabulary of iteration• the open function• demos

Page 3: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

def get_one_digit_nums():print("START")nums = []i = 0while i < 10:

nums.append(i)i += 1

print("END")return nums

for x in get_one_digit_nums():print(x)

how many times is the word "START" printed?

Page 4: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

def get_one_digit_nums():print("START")nums = []i = 0while i < 10:

nums.append(i)i += 1

print("END")return nums

for x in get_one_digit_nums() [0,1,2,3,4,5,6,7,8,9]:print(x)

how many times is the word "START" printed?

Page 5: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

def get_one_digit_nums():print("START")nums = []i = 0while i < 10:

nums.append(i)i += 1

print("END")return nums

for x in get_one_digit_nums():print(x)

time

running get_one_digit_nums code looping over results and printing

stage 1 stage 2STA

RT

END

Page 6: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

def get_primes():print("START")nums = []i = 0while True:

if is_prime(i):nums.append(i)

i += 1print("END")return nums

for x in get_primes():print(x)

what does this code do?assume there is an earlieris_prime function

Page 7: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

def get_primes():print("START")nums = []i = 0while True:

if is_prime(i):nums.append(i)

i += 1print("END")return nums

for x in get_primes():print(x)

to make this work, we'll need to learn acompletely new kind of function, the generator

Page 8: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

def get_primes():...

for x in get_primes():print(x)

time

... continue forever ...

what we want:

Page 9: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

def get_primes():...

for x in get_primes():print(x)

time

... continue forever ...

run get_primes just longenough to get one prime LAZY (contrast with "eager")

Page 10: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

def get_primes():...

for x in get_primes():print(x)

time

... continue forever ...

run get_primes just longenough to get one prime LAZY (contrast with "eager")

print one number

Page 11: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

def get_primes():...

for x in get_primes():print(x)

time

... continue forever ...

run get_primes just longenough to get one prime LAZY (contrast with "eager")

print one number

RESUME get_primes to get another number

Page 12: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

def get_primes():...

for x in get_primes():print(x)

time

... continue forever ...

run get_primes just longenough to get one prime LAZY (contrast with "eager")

print one number

RESUME get_primes to get another number

we will stop and resume runningget_primes many times, even

though we only call it once

Page 13: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

def get_primes():...

for x in get_primes():print(x)

time

... continue forever ...

run get_primes just longenough to get one prime LAZY (contrast with "eager")

print one number

RESUME get_primes to get another number

we will stop and resume runningget_primes many times, even

though we only call it once

functions with this stop/resumebehavior are called generators

Page 14: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

def get_primes():... some code ...

yield VALUE

... more code ...

any function containing the yield keyword anywhere is a generator

if you see this, all bets are offregarding how you currentlyunderstand functions to behave

Page 15: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

gen def get_primes():... some code ...

yield VALUE

... more code ...

any function containing the yield keyword anywhere is a generator

if you see this, all bets are offregarding how you currentlyunderstand functions to behave

should we even consider it a function?

?

Page 16: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

gen def get_primes():... some code ...

yield VALUE

... more code ...

any function containing the yield keyword anywhere is a generator

if you see this, all bets are offregarding how you currentlyunderstand functions to behave

should we even consider it a function?

?

Guido van RossumPython's Benevolent Dictator for Life

(until recently) https://www.python.org/dev/peps/pep-0255/#bdfl-pronouncements

Should we "introduce another new keyword (say, gen or generator) in place of def"?

Page 17: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

gen def get_primes():... some code ...

yield VALUE

... more code ...

any function containing the yield keyword anywhere is a generator

if you see this, all bets are offregarding how you currentlyunderstand functions to behave

should we even consider it a function?

?

Guido van RossumPython's Benevolent Dictator for Life

(until recently) https://www.python.org/dev/peps/pep-0255/#bdfl-pronouncements

Argument for def: "generators are functions, but with the twist that they're resumable"

Argument for gen: "a yield statement buriedin the body is not enough warning that the semantics are

so different"

Page 18: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

def get_primes():... some code ...

yield VALUE

... more code ...

Guido van RossumPython's Benevolent Dictator for Life

(until recently) https://www.python.org/dev/peps/pep-0255/#bdfl-pronouncements

Argument for def: "generators are functions, but with the twist that they're resumable"

Argument for gen: "a yield statement buriedin the body is not enough warning that the semantics are

so different"

always scan a function for yieldswhen trying to understand it

Page 19: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

Iterators/Generators (Part 2)

Outline• when normal functions aren't good enough• yield keyword by example• the scary vocabulary of iteration• the open function• demos

Page 20: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

yield by example (note, PyTutor does a bad job showing generators)

def f():yield 1yield 2yield 3

for x in f():print(x)

def f():print("A")yield 1print("B")yield 2print("C")yield 3

for x in f():print(x)

def f():yield 1yield 2yield 3

for x in f():print(x)

for x in f():print(x)

def f():yield 1yield 2yield 3

for x in f():for y in f():

print(x, y)

def f():yield 1yield 2yield 3

gen = f()for x in gen:

print(x)

def f():yield 1yield 2yield 3

gen = f()print(next(gen))print(next(gen))

Page 21: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

Iterators/Generators (Part 2)

Outline• when normal functions aren't good enough• yield keyword by example• the scary vocabulary of iteration• the open function• demos

Page 22: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

for x in :# some code

???

The Vocabularyof Iteration

can go here

Page 23: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

for x in :# some code

iterable

The Vocabularyof Iteration

can go here

Page 24: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

for x in :# some code

iterable

sequence

list str tuple range

is ais a

is an

The Vocabularyof Iteration

can go here

Page 25: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

for x in :# some code

iterable

sequence

list str tuple range

is ais a

is an

The Vocabularyof Iteration

can go here

can beconverted

to a

Example:L = list("ABC")

Page 26: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

for x in :# some code

iterable

sequence

list str tuple range

is ais a

is an

The Vocabularyof Iteration

can go here

dict.keys() dict.values()

can beconverted

to a

Example:L = list(d.keys())

Page 27: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

for x in :# some code

iterable

sequence iterator

list str tuple range

is ais a

is an is an can give you an

The Vocabularyof Iteration

can go here

dict.keys() dict.values()

can beconverted

to a

Example:it = iter("ABC")first = next(it)

Page 28: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

for x in :# some code

iterable

sequence iterator

generator object

generator function

list str tuple

yield keyword

range

contains a

returns a

is ais a

is an is an can give you an

The Vocabularyof Iteration

is an

can go here

dict.keys() dict.values()

can beconverted

to a

Example:gen_obj = gen_function(...)first = next(gen_obj)

Page 29: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

for x in :# some code

iterable

sequence iterator

generator object

generator function

list str tuple

yield keyword

range

contains a

returns a

is ais a

is an is an can give you an

The Vocabularyof Iteration

is an

can go here

dict.keys() dict.values()

can beconverted

to a

careful!• many use "generator" to refer to

both a generator function and a generator object

• some use "generator" and "iterator" as synonyms

Example:gen_obj = gen_function(...)first = next(gen_obj)

Page 30: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

for x in :# some code

iterable

sequence iterator

generator object

generator function

list str tuple

yield keyword

range

contains a

returns a

is ais a

is an is an can give you an

The Vocabularyof Iteration

is an

can go here

dict.keys() dict.values()

can beconverted

to a

careful!• many use "generator" to refer to

both a generator function and a generator object

• some use "generator" and "iterator" as synonyms

let's differentiate these better...

Page 31: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

is x iterable?if this works, then yes:

iter(x)

is y an iterator?if this works, then yes:

next(y)

returns an iterator over x

returns next value from y

Page 32: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

is x iterable?if this works, then yes:

y = iter(x)

is y an iterator?if this works, then yes:

next(y)

returns an iterator over x

returns next value from y

Page 33: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

x = [1,2,3]y = enumerate([1,2,3])z = 3

Can you classify x, y, and z?

Things to try:

iter(x)next(x)etc.

Page 34: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

Iterators/Generators (Part 2)

Outline• when normal functions aren't good enough• yield keyword by example• the scary vocabulary of iteration• the open function• demos

Page 35: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

Reading Files

path = “file.txt”f = open(path)

open(…) function is built in

Page 36: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

Reading Files

path = “file.txt”f = open(path)

it takes a string argument,which contains path to a file

This is a test!321Go!

file.txt

c:\users\meena\my-doc.txt

/var/log/events.log

../data/input.csv

Page 37: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

Reading Files

path = “file.txt”f = open(path)

it returns a file object

This is a test!321Go!

file.txt

file objects are iterators!

Page 38: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

Reading Files

path = “file.txt”f = open(path)

for line in f:print(line)

This is a test!321Go!

file.txt

Output

This is a test!

3

2

1

Go!

Page 39: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

Iterators/Generators (Part 2)

Outline• when normal functions aren't good enough• yield keyword by example• the scary vocabulary of iteration• the open function• demos

Page 40: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

Demo 1: add numbers in a file

Goal: read all lines from a file as integers and add them

Input:• file containing 50 million numbers between 0 and 100

Output:• The sum of the numbers

Example:

prompt> python sum.py2499463617

Two ways:• Put all lines in a list first• Directly use iterable file

Bonus: create generator functionthat does the str => int conversion

Page 41: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

Demo 2: handy functions

Learn these:• enumerate• zip

Bonus: tuple packing/unpacking

Page 42: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

Demo 3: sorting files by line length

Goal: output file contents, with shortest line first

Input:• a text file

Output:• print lines sorted

Page 43: [220] Iterators / Generators · 2020-03-23 · defget_primes():... forx inget_primes(): print(x) time... continue forever ... run get_primesjust long enough to get one prime LAZY

Demo 4: matrix load

Goal: load a matrix of integers from a file

Input:• file name

Output:• generator that yields lists of ints

1,2,34,5,67,8,9 generator [1,2,3]

...