- Title: [[Raymond Hettinger - Transforming Code into Beautiful, Idiomatic Python]]
- Type: #source/video
- Author: [[@Raymond Hettinger]]
- Reference: https://www.youtube.com/watch?v=OSGv2VnC0go
- Published at:
- Reviewed at: [[2021-10-06]]
- Links:
---
## Basics
- replace index manipulations with python's core looping idioms (when not doing numpy code)
- learn advanced techniques with for-else and to arg form of iter()
- aim for fast, clean idiomatic python.
### for-in
Python's for loop is more like a for-each and leverages an underlying iterator construct (not index based counter). But lots of things play well with iterables (not just for-in)
```python
for i in [0, 1, 2, 3, 4, 5]:
print i ** 2
# in python < 2 range reifies the list, xrange is a lazy iterator
# python 3 fixes that
for i in range(6):
print i ** 2
```
### loop backwards
```python
for i in range(len(arr) -1, -1, -1):
print arr[i]
# both cleaner and faster
for a in reversed(arr):
print a
```
### for with index
```python
for i, a in enumerate(arr):
print i, a
```
### iterate over 2 collections
`for name, color in zip(names, colors):`
`izip` is similar but zips as a lazy iterator (supposedly better for L1 [[cache locality]]). Python 3's `zip` is basically `izip` so you have to force it to be iterated over or into a collection
### iterate in sorted order
`for color sorted(colors):`
`for color sorted(colors, reversed=True):`
```python
def compare(c1, c2):
...
sorted(colors, cmp=compare)
# or just sort by a specific property (key)
# key based sorting is faster because of fewer
# custom comparator method calls
sorted(colors, key=len)
# python 3 no longer has custom comparator functions?
```
### Call a function until a sentinel value
```python
blocks = []
while True:
block = f.read(32)
if block == '':
break
blocks.append(block)
# iter takes a second arg to denote the sentinel value
bocks = []
for block in iter(partial(f.read, 32), ''):
blocks.append(block)
```
### Multiple loop exit points
```python
def find(seq, target):
found = False
for i, value in enumerate(seq):
if value == target:
found = True
break
if not found:
return -1
return i
def find(seq, target):
for i, value in enumerate(seq):
if value == target:
break
else:
# i.e. "no-break"
# due to Donald Knuth. Calling it else made a lot of
# sense when all structured programming (including for loops)
# were build on conditional jumps and gotos - everyone
# expected an else clause
return -1
return i
```
## Dictionary skills
- Master dict fundamentals
`for k in d:` iterates over keys.
`for k in d.keys():` if you need to mutate the dictionary while iterating, first makes a copy
`for k, v in d.items():` items returns a list of key-value tuples. `d.iteritems()` is a lazy iterator