Using the list literals []
(brackets), we construct a for
loop from within.
words = "This is a such a long course".split()
words
[len(word) for word in words]
List comprehensions are a tool for transforming one list (or any container object in Python3) into another list. This is a syntactic work around for the long standing filter()
and map()
functions in python.
(New to Python 3)
Using the set literals {}
, we construct a for
loop from within.
Recall the difference between a set and dictionary is whether there is a key:value pair within the curly brackets. When there is a key:value pair within the brackets, it's a dictionary. When there are only values, it's a set. Use
type()
if you are unsure.
{len(word) for word in words}
(New to Python 3)
Using the set literals {}
and assigning a key value pair {key : value}
, we construct a for
loop from within.
# Create two lists: one full of values and another of equal length full of keys.
list_of_values = [1,2,3,4,5]
list_of_keys = ['a','b','c','d','e']
length_of_the_lists = len(list_of_values)
{list_of_keys[i]:list_of_values[i] for i in range(length_of_the_lists)}
if
statements in comprehensions¶# Quickly produce a series of numbers
[i for i in range(10)]
[i for i in range(10) if i > 5 ]
else
statements aren't valid in a comprehension, so the code statement needs to be kept simple.
[i for i in range(10) if i > 5 else "hello"]
Concise if-then
statements
<this_thing> if <this_is_true> else <this_other_thing>
x = 4
"Yes" if x > 5 else "No"
x = 6
"Yes" if x > 5 else "No"
["Yes" if x > 5 else "No" for x in range(10)]
[i for i in range(5)]
[j for j in range(-5,0)]
[[i,j] for i in range(5) for j in range(-5,0)]
Comprehensions not only make our code more concise, they also increase the speed of our code
%%timeit
container = []
for i in range(1000):
container.append(i)
%%timeit
container = [i for i in range(1000)]
The comprehension expression takes roughly half the time!
# Say we create a string object letter
letter = 'z'
# Then we use letter as a placeholder
letters = ['a','b','c','d']
for letter in letters:
print(letter)
letter # Letter got over written!!!
Now let's do the same thing with a comprehension
letter = 'z'
[letter for letter in letters]
letter
What this means is the list comprehensions offer us more consistency and generate less issues when we arbitrarily assign named values for placeholders when using for
loops
Generators are similar to functions; however, rather than use the return
keyword, we leverage the yield
keyword. If you use the yield
keyword once in a function, then that function is a generator.
def gen123():
yield 1
yield 2
yield 3
gen123
g = gen123() # initiate in an object
g
Behaves just like an iterator; however, the next thing being demanded isn't the next item, but rather the next computation
next(g)
next(g)
next(g)
next(g)
Note that each call to a generator returns a new generator object.
h = gen123()
i = gen123()
h is i
(expr(item) for item in iterable)
(i for i in range(10))
list((i for i in range(10)))
sum(i for i in range(10))
This is really useful if we want to calculate values on demand rather than loading an entire series into memory.
# from 1 to 100,000, how many values are divisible by 13?
sum(1 for i in range(100000) if i%13)
Part of the python standard library. Itertools deals with pythons iterator objects. This provides a robust functionaliy for iterable sequences. Functions in itertools operate on iterators to produce more complex iterators.
We saw two last time when discussing lambda
functions: filter()
and map()
.
Some iteration tools produce scalar values, other produce other iterable objects.
any()
¶any(name == name.title() for name in ["London","New York","Russia",'cat','bus'])
any(len(name) > 10 for name in ["London","New York","Russia",""])
all(name == name.title() for name in ["London","New York","Russia",'cat','bus'])
all(len(name) > 0 for name in ["London","New York","Russia",""])
sum(i for i in range(100))
min(i for i in range(100,1000) if i % 17 == 0)
max(i for i in range(100,1000) if i % 17 == 0)
zip()
¶syncs two series of numbers up into tuples.
a = list(range(10))
b = list(range(-10,0))
zip(a,b) # It's own object type
dir(zip(a,b))
[item for item in zip(a,b)]
Generates an index and value tuple pairing
my_list = 'Iterator tools are useful to move across iterable objects in complex ways.'.split()
enumerate(my_list)
[i for i in enumerate(my_list)]
import itertools
Permutations of all potential combinations
x = ['a','b','c','d']
[i for i in itertools.combinations(x,2)]
# Note that we can also unpack an iterable with a constructor
list(itertools.combinations(x,2))
# combinations with replacement
list(itertools.combinations_with_replacement(x,4))
list(itertools.permutations(x))
Creates a count generator.
counter = itertools.count(start=0,step=.3)
next(counter)
next(counter)
next(counter)
list(zip(itertools.count(step=5),"Georgetown"))
list(itertools.repeat("a",10))
lazily concatenate lists together without the memory overhead of duplication.
list(itertools.chain('ABC', 'DEF'))
Slices like we would normally do on a list, but does so as an iterator.
[i for i in itertools.islice('abcd',2)]