Use reversed
:
colors = ['red', 'green', 'blue'] for color in reversed(colors): print(color)
Use enumerate
:
colors = ['red', 'green', 'blue'] for i, color in enumerate(colors): print("{} -> {}".format(i, color))
names = ['raymond', 'rachel', 'matthew'] colors = ['red', 'green', 'blue', 'yellow'] for name, color in zip(names,colors): print("{} -> {}".format(name, color))
Note that the lengths are different.
Use sorted
:
colors = ['red', 'green', 'blue'] for color in sorted(colors): print(color)
To sort by length:
colors = ['red', 'green', 'blue'] for color in sorted(colors, key=len): print(color)
Python's break
only breaks out of one loop. To break out from two, make it a single loop. So:
for x in range(width): for y in range(height): <do something>
Create a range:
def range_2d(width, height): for x in range(width): for y in range(height): yield x, y
Then, you can do:
for x, y in range_2d(width, height): <do something>
Instead of:
for i in v: for j in w: <do something>
you can do
it = ( (i,j) for i in v for j in w ) # creates a GENERATOR for i,j in it: <do something>
d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'} for k in d: print k
If you want to change the dictionary while you loop, loop over d.keys()
:
for k in d.keys(): if k.startswith('r'): del d[k]
for v in d.values() <do stuff>
for key, value in d.items() print("{} --> {}".format(key, value))
d = dict(zip(names, colors))
Use d.get
. d.get(item,0)
gives d[item]
if possible and 0
otherwise.
d = {} v = [0,0,0,1,1,1,1,1,1,2,2,0,2,1] for x in v: d[x] = d.get(x,0) + 1
There is also d.setdefault(key, default_value)
, which also creates the d[key]
if it does not exist already.
One can also use defaultdict(type)
, which creates an “empty” dictionary with values of type
.
For instance, to create a dictionary grouping stings of names
by length:
from collections import defaultdict d = defaultdict(list) for name in names: key = len(name) d[key].append(name)
If key
does not exist, it creates it and sets the default value for list
, which is an empty list. (And for int
it is 0
.)
v = [ 'a', 'b', 'c', 'd' ] w = [ 1, 2, 3, 4 ] my_dict = { letter : number for letter, number in zip(v,w) if number != 2 }
gives my_dict
as { 'a' : 1, 'c' : 3, 'd' : 4 }
.
Use *
for optional arguments with no default value.
def my_fct(x, *v): print('First value is {}'.format(x)) if v: # runs if v is not empty print('The other values are:') for value in v: print(value)
You can call it with my_fct(3)
, my_fct(3,4)
, my_fct(3,4,5)
, etc.
Also, if v = [1, 2]
, then my_fct(3,*v)
is the same as my_fct(3,1,2)
.
In Python 3, if
def f(x, y, *, z=0, w=1): return x+y+z+w
you cannot call it as f(1,2,3,4)
, you must call it with f(1,2,x=3,w=4)
, i.e., the keyword arguments must be entered as keywords.
Instead of
def f(x,y): return x + y
do
f = lambda x, y: x + y
If v
is a list and f
is a function, then
fv = map(f,v)
applies f
to entries of v
. In Python 3 it is iterable. (To make a list, do fv = list(map(v))
.)
Now if test
is a conditional function,
testv = filter(test,v)
gives only the elements of v
satisfying test
. Similar to
testv = [ x in v if test(x) ]
but in Python 3 it gives an iterable, not a list.
You can use the else
part of a for loop. So, instead of
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
do
def find(seq, target): for i, value in enumerate(seq): if value == target: found = True break else: return -1 return i
The else
is like a nobreak
: if the look finished normally, it skips the else
part. If there is a break in the look, it runs the else
part.
To save functions from recomputing the same value (with the expense of saving the computed values in memory) is to use@cache
. So, instead of:
def my_fct(x, saved={}): if x in saved: return saved[x] <compute result> saved[x] = result return result
do
@cache def my_fact(x): <compute result> return result
Instead of:
f = open('data.txt') try: data = f.read() finally: f.close()
do
with open('data.txt') as f: data = f.read()
Instead of
sum([i**2 for i in range(10)])
do
sum(i**2 for i in range(10))
from collections import namedtuple Color = namedtuple('Color',['hue', 'saturation', 'luminosity']) p = Color(170, 0.1, 0.6) if p.saturation > 0.5: print('Bright!') if p.luminosity > 0.5: print('Light!')
See also: https://www.geeksforgeeks.org/namedtuple-in-python/
If you want to loop over the squares of integers from 1 to 1000, instead of creating the list
[ i**2 for i in range(1,1001)]
and looping, create the generator/iterator:
( i**2 for i in range(1,1001))
It's better in most cases to return generators/iterators instead of lists. So instead of:
def cubes(n): res = [] for i in range(n): res.append(i**3) return res
you can do
def cubes(n): for i in range(n): yield i**3
We can make it a list if we want to with list(cubes(10))
, but we can use to iterate (only once per call), like:
for i in cubes(10): <do something with i>
Or, to extract the first three elements:
c = cubes(100000) next(c) next(c) next(c)
x = 1 if <condition> else 0
number = 100000000 print('The number is {:,}'.format(number))
a, b, c = (1, 2, 3, 4, 5)
gives an error. In Python 3 we can do
a, b, *c = (1, 2, 3, 4, 5)
gives an a = 1
, b = 2
, c = [3, 4, 5]
.
a, b, *_ = (1, 2, 3, 4, 5)
gives an a = 1
and b = 2
.
a, b, *c, d = (1, 2, 3, 4, 5)
gives an a = 1
, b = 2
, c = [3, 4]
, and d = 5
.
The following values are treated as False: “”
(empty string), 0
, 0.0
, []
(empty list), ()
(empty tuple), {}
(empty dictionary), False
, None
. If variable
then is any of those, then
if variable: print('OK')
will not print OK
, but will otherwise.
You cannot create and empty set wit my_set = {}
as it creates an empty dictionary. So, you do it with my_set = set()
.
This also works for lists, tuples or dictionaries:
empty_list = [] empty_list = list() empty_tuple = () empty_tuple = tuple() empty_dict = {} empty_dict = dict()