Python Shortcuts

*args and **kwargs

def func1(arg1, arg2, arg3): # you need to pass all args for this func
  print(arg1, arg2, arg3)
  
def func2(arg1=None, arg2=None, arg3=None): # you don't need to pass all args for this func
  print(arg1, arg2, arg3)

args = [1, 2, 3]
kwargs = {'arg2': 2, 'arg1': 1, 'arg3': 3}

func1(*args) # *args unpacks the args collection and passes the values
# Outputs: 1 2 3

func1(**kwargs) # **kwargs unpacks the args dict and passes the values to arguments matching the keys. Similar to doing *kwargs.values() but keys determine which value is passed to which argument.
# Outputs: 1 2 3

func1(*kwargs.values()) # single * doesn't match the keys to arguments
# Outputs: 2 1 3

# **kwargs makes your function very flexible:
def func3(**kwargs):
  print(kwargs)
func3(**kwargs)
# Outputs: {'arg2': 2, 'arg1': 1, 'arg3': 3}

# **kwargs makes your function very flexible:
def func3(**kwargs):
  print(kwargs)
func3(**kwargs)
# Outputs: {'arg2': 2, 'arg1': 1, 'arg3': 3}

Combine lists with zip()

names = ['jim', 'joe', 'bill']
ages = [32, 25, 19]
occupation = ['doctor', 'dentist', 'student']
print(list(zip(names, ages, occupation))) # zip() returns an object
# Outputs: [('jim', 32, 'doctor'), ('joe', 25, 'dentist'), ('bill', 19, 'student')]

# Where it's useful:
for name, age in zip(names, ages):
    if age > 30:
        print(name)
# Outputs: jim

For Else and While Else

search = [1, 2, 3, 4, 5, 6, 7]
target = 8

for element in search:
  if element == target:
    print('Found it!')
    break
else: # if the loop was done w/o breaking
  print('Didn\'t find it!')
# Outputs: Didn't find it!

i = 0
while i < len(search):
  element = search[i]
  if element == target:
    print('Found it!')
    break
  i += 1
else: # if the loop was done w/o breaking
  print('Didn\'t find it!')
# Outputs: Didn't find it!

Inline conditions

x = 1 if 2 > 3 else 0 # else if required here
print(x)
# Outputs: 0

Unpack a collection of items and assign them to variables

tup = (1, 2, 3, 4, 5)
a, b, c, d, e = tup
print(a, b, c, d, e)
# Outputs: 1 2 3 4 5

list = [0, 2, 4, 6, 8]
a, b, c, d, e = list
print(a, b, c, d, e)
# Outputs: 0 2 4 6 8

string = "hello"
a, b, c, d, e = string
print(a, b, c, d, e)
# Outputs: h e l l o

dic = {'a': 1, 'b': 2}
a, b = dic # assigns keys
print(a, b)
# Outputs: a b

a, b = dic.values() # assigns values
print(a, b)
# Outputs: 1 2

a, b = dic.items() # assigns items
print(a, b)
# Outputs: ('a', 1) ('b', 2)

Assign multiple variables in one line

width, height = 400, 300
print (width, height)
# Outputs: 400 300

# You can swap their values:
width, height = height, width
print (width, height)
# Outputs: 300 400

Initialize a collection in one line

x = [i for i in range(10)]
print(x)
# Outputs: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# Conditions
x = [i for i in range(10) if i % 2 == 0]
print(x)
# Outputs: [0, 2, 4, 6, 8]

# Multiple loops
x = [i*j for i in range(3) for j in range (3)]
print(x)
# Outputs: [0, 0, 0, 0, 1, 2, 0, 2, 4]

# Creating a 2D array
x = [[0 for _ in range(2)] for _ in range(3)] # if you are not going to use the iterator index, you can use _ instead
print(x)
# Outputs: [[0, 0], [0, 0], [0, 0]]

Itertools

import itertools

lst = [1, 2, 3, 4, 5]
sum_list = itertools.accumulate(lst)
print(list(sum_list))
# Outputs: [1, 3, 6, 10, 15]

lst2 = ['a', 'b', 'c', 'd', 'e']
chain_list = itertools.chain(lst, lst2) # returns an iterator object, which is more memory efficient than merging the list
print(list(chain_list)) # here we did create a merge list for printing but you could loop through chain_list without creating a new list
# Outputs: [1, 2, 3, 4, 5, 'a', 'b', 'c', 'd', 'e']

show = [1, 0, 1, 0, 1]
compressed_list = itertools.compress(lst, show)
print(list(compressed_list))
# Outputs: [1, 3, 5]