Python's "for" loops are single-purposed: they can loop over an iterable item-by-item. That's it.

The "for" loop itself can't loop in reverse or loop over multiple iterables.

For this reason, looping helpers are a VERY big deal in #Python.

Let's talk about looping helpers. 🧵
Want to loop over an iterable in the reverse direction? If it's a reversible iterable (lists, tuples, dictionaries, etc), you can use the reversed helper:

>>> colors = ["pink", "blue", "green"]
>>> for color in reversed(colors):
... print(color)
...
green
blue
pink
Note that the "for" loop isn't reversing here: reversed is!

The built-in reversed function accepts an iterable and returns a lazy iterable that provides each item from the original iterable in the reverse order.

>>> r = reversed(colors)
>>> next(r)
'green'
>>> next(r)
'blue'
Want to loop while counting upward? Python's enumerate function can help!

>>> for n, color in enumerate(colors, start=1):
... print(n, color)
...
1 pink
2 blue
3 green

Again the "for" loop isn't doing the work: enumerate is! The enumerate function returns a lazy iterable.
But what about that magic "n, color" thing?

That's tuple unpacking.

enumerate returns an iterable of tuples:

>>> enumerate(colors)
<enumerate object at 0x7efe54e6c6c0>
>>> list(enumerate(colors))
[(0, 'pink'), (1, 'blue'), (2, 'green')]

And we're unpacking them as we loop!
Need to loop over multiple iterables at once? That's what zip is for!

>>> colors = ["pink", "blue", "green"]
>>> animals = ["duck", "walrus", "monkey"]
>>> for color, animal in zip(colors, animals):
... print(color, animal)
...
pink duck
blue walrus
green monkey
The built-in zip function accepts any number of iterables and returns a lazy iterable that provides tuples of the n-th item from each of the given iterables (1st item from each, second from each, and so on).

Like enumerate, zip also pairs nicely with tuple unpacking.
What if you don't even have an "iterable" and you just need to increment or decrement numbers?

Python's range function can return an iterable that'll do that for you!

>>> for n in range(50, 300, 50):
... print(n)
...
50
100
150
200
250
These are just some of Python's many looping helpers.

Here are more examples from the itertools module:

• itertools.islice: stop after N items or skip the first N items
• itertools.chain: lazily "chain" iterables together
• itertools.takewhile: loop while a condition is true
You can also use generators & iterators to invent your own lazy looping helpers in Python.

This one acts like enumerate, but it counts downward:

def denumerate(iterable, start=0):
n = start
for item in iterable:
yield n, item
n -= 1
More on some of the built-in looping helpers:

➡️ enumerate: pym.dev/looping-with-i…
➡️ zip: pym.dev/looping-over-m…
➡️ reversed: trey.io/reversed
➡️ range: trey.io/range

On making your own looping helpers: trey.io/making-looping…
Want some practice with looping helpers? Try out @PythonMorsels! Lots of Python Morsels exercises involve both using and inventing own looping helpers.

If you enjoyed this thread:

1. Follow me, @treyhunner, for more of these
2. Retweet to share with others

• • •

Missing some Tweet in this thread? You can try to force a refresh
 

Keep Current with Trey Hunner (Python trainer)

Trey Hunner (Python trainer) Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

More from @treyhunner

May 25
I recommend against using the file readlines method in #Python.

Many folks assume that readlines returns a lazy iterable (an iterator) of lines. But the readlines method returns a list, not an iterator!

These are equivalent:

lines = my_file.readlines()
lines = list(my_file)
If you need to lazily loop over lines in a file, you can loop over the file object itself to do that:

for line in my_file:
...

You can use a file like any other iterable. For example you can use it in a comprehension:

non_empty = [line for line in my_file if line.strip()]
When I need to make a list of all lines in a file, I use the list constructor:

lines = list(my_file)

I find that clearer than this:

lines = my_file.readlines()

☝ That second line can lead newer Pythonistas to assume this is okay:

for line in my_file.readlines():
...
Read 5 tweets
May 24
Ever wondered "what's a float"?

floating point number (a.k.a. float): an object used for representing real numbers using a fairly accurate approximation

Let's talk about floats work in #Python!

#TerminologyTuesday
Floating point numbers are an approximation of their decimal equivalents.

They're super useful for most uses, but they can't be relied on for exact precision.

You can't assume that an exact equality comparison with floating point numbers will work:

>>> 0.1 + 0.02 == 0.12
False
Adding 0.1 and 0.02 results in a number that is VERY slightly different from the 0.12 number that we'd expect:

>>> 0.1 + 0.02
0.12000000000000001

This might seem like a huge problem, but it's usually not! This imprecision typically only causes trouble with strict equality.
Read 11 tweets
May 19
I love Python's pathlib module. 💖🐍🗃

Whenever I need to ask a question about a file path in #Python, I default to using pathlib.

Let's talk about some of my most common uses for pathlib and compare them to their non-pathlib alternatives. 🧵
Assume all the below examples include the "filename" and "path" variables defined like this:

>>> from pathlib import Path
>>> filename = "my_file.txt"
>>> path = Path(filename)

Also assume that we've imported os, glob, and os.path as needed:

>>> import glob, os, os.path
Get an absolute path (from a path that may be relative or may already be absolute).

💾 Old approach:

>>> filename = os.path.abspath(filename)

✨ pathlib approach:

>>> path = path.resolve()
Read 12 tweets
May 17
Here's a deceptively fuzzy #Python term: mutable object. 🤔

mutable object: an object whose "value" can change

But what does "value" really mean?

#TerminologyTuesday
Lists are mutable because a list object can be changed.

>>> numbers = [2, 1, 3]
>>> numbers.append(4)
>>> numbers
[2, 1, 3, 4]

If two variables refer to the same list, any change to the list will be reflected by both variables:

>>> x = numbers
>>> x.clear()
>>> numbers
[]
Strings are immutable in #Python. That means that there is no way to "change" a string object in Python.

Try as hard as you might, you cannot change strings. You can only make NEW strings.

name = "Trey"
name = name + "!" # makes a new string
name += "!" # same as above
Read 12 tweets
May 9
Need to flatten a list-of-lists (or an iterable-of-iterables) in #Python?

There are about 5 "right" ways to do it and one "wrong" way (for some values of right and wrong). Which way you choose depends on your preference.
You may reach for nested loops:

names = []
for group in groups:
for name in group:
names.append(name)

But the extend method can replace the inner loop:

names = []
for group in groups:
names.extend(group)

If you prefer, += works as well:

names += group
I prefer to replace that for-for-append pattern with a comprehension:

names = [
name
for group in groups
for name in group
]

I find 2-loop comprehensions readable as long as each "for" component is on its own line of code. Whitespace is your friend! 💓
Read 7 tweets
Feb 14
Strings in #Python have a ton of methods on them.

I recommend learning these 10 first:

• join
• split
• replace
• format
• startswith
• endswith
• strip
• casefold
• splitlines
• count

Let's talk about what these methods do and why I recommend these ones first. 🧵
1️⃣ The string join method accepts an iterable of strings to join together.

It should be called on the separator you'd like to join by (e.g. " ", "\n", ",", ""). This is a string method: it's " ".join(my_list) and not my_list.join(" ").

2️⃣ The string split method is the opposite of join.

split accepts an optional separator:

time = "02:27"
h, m = time.split(":")

The default separator is "any consecutive whitespace characters".

Splitting can also be limited with a maxsplit arg.

Read 19 tweets

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3/month or $30/year) and get exclusive features!

Become Premium

Don't want to be a Premium member but still want to support us?

Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal

Or Donate anonymously using crypto!

Ethereum

0xfe58350B80634f60Fa6Dc149a72b4DFbc17D341E copy

Bitcoin

3ATGMxNzCUFzxpMCHL5sWSt4DVtS8UqXpi copy

Thank you for your support!

Follow Us on Twitter!

:(