Skip to content

Instantly share code, notes, and snippets.

@beyonddream
Last active July 4, 2023 19:02
Show Gist options
  • Save beyonddream/a43e067db6336b03a2c4fc5da59ba507 to your computer and use it in GitHub Desktop.
Save beyonddream/a43e067db6336b03a2c4fc5da59ba507 to your computer and use it in GitHub Desktop.
Python Coding cheat sheet

Python Coding Tips for intermediate programmers

Note: Most of the example codes are adapted from the excellent 'Learning Python' by Fabrizio Romano

Python code style

Refer to PEP8 - https://www.python.org/dev/peps/pep-0008/

Python code organization

package, module

module

  • a .py file - a python module

package

  • group set of modules together
  • a folder which has .py files
  • it must contain a __init__.pyfile inside this folder for it to qualify as a package
  • as of 3.3 , __init__.py is not strictly required

Class

class Bike:
  def __init__(self, color, frame_material):
   self.color = color
   self.frame_material = frame_material
   
  def print_detail(self):
   print("color : %s, frame_material: %s" % (self.color, self.frame_material))  

red_bike = Bike('Red', 'Carbon fiber')
red_bike.print_detail()  # color : Red, frame_material: Carbon fiber

DataClass

from dataclasses import dataclass

@dataclass
class Employee:
  """ Immutable public data of employee information """
  first_name: str
  middle_name: str
  last_name: str
  age: str
  department_id: int


employee1 = Employee("John", "", "Doe", 23, 1)
employee2 = Employee("Jane", "", "Doe", 20, 2)

Scopes

Order of scope evaluation while trying to find a name in a namespace

LEGB (Local, Enclosing function, Global, Built-in)

If you have a function and want to modify a global variable within the function (Not recommended but if needed)

x = 10

def func():
 global x # 'x' is in global namespace
 x += 1
 
func()
# x is now 11

If you have a nested function and want to modify a variable in the outer scope (Not recommended but if needed)

def outer():
 x = 10
 
 def inner():
  nonlocal x # modifies outer 'x'
  x += 1

 inner()
 # x is now 11

Imports

from module_name import identifier

from module_name import identifier as better_identifier

import module_name
 
from .module_name import identifier # number of dots specify the number of folders to backtrack up and one 'dot' is current folder

Numbers

Almost everything is an object in python

a = 10 # a is pointing to an object containing 10 which is of int data type

a ** b # ** is a power operator

a // b # integer division

a / b  # true division with fractional part

int(1.75) # use this if you want to truncate the fractional part instead of flooring it.

a = True  # boolean true
a = False # boolean false

boolean operators are : not, and, or

True/False are subclasses of integer

pi = 3.141 # real stored in 64 bits - double precision floating point format

c = 3.14 + 2.73j # complex number

c.real # 3.14
c.imag # 2.73

Immutable Sequences

string, tuples, bytes

string # unicode code points

s = ""
s = ''
#multiline string below
s = """ 
"""
s = '''
'''
s_encoded = s.encode('utf-8') # utf-8 encoded 
s_encoded.decode('utf-8')

s_bytes = b"A bytes object" # a bytes object

s = "arun"
s[0] # 'a'

s[:3] # 'aru' - s[start:stop:step] - stop is exclusive

s[:] # make a copy of original

s[::-1] # copy of original in reverse order

t = () # tuple, a sequence of arbitary python objects

t = (42, ) # need a comma for one element tuple

a, b, c = 3, 2, 1 # multiple assignments

2 in t # membership test

a, b = b, a # pythonic way to swap two variables

tuples can be used as keys in dictionaries

Mutable Sequences

List, bytearray, set, dict

[] # empty list

list() # same as [] 

a = [1, 2, 3]

a = [x + 2 for x in [1, 2, 3]] # a = [3, 4, 5]

list((1, 2, 3)) # => [1, 2, 3] ; convert a tuple into a list

list('hello') # ['h', 'e', 'l', 'l', 'o'] ; list from string

methods on list:

a.append(5) # [3, 4, 5, 5]

a.count(5) # how many 5 are there in a

a.extend([6, 7]) # [3, 4, 5, 5, 6, 7]

a.index(4) # 1 ; position of 4 in [3, 4, 5, 5, 6, 7]

operations on list:

min(a) # 3
sum(a) # 30

bytearray:

name = bytearray(b'Arun')

str to bytearray:

s1 = "github"
# we cannot directly update s1 since it is immutable
b1 = bytearray(s1.encode("utf-8"))
b1[0] = ord("h")
s2 = b1.decode("utf-8")
print(s2) # prints "hithub"

set:

a = set() # set

a.add(1)
a.add(2)
a.add(3)
a.add(1) 

#a = {1, 2, 3}

1 in a # True
1 not in a # False

frozenset([1, 2]) # immutable set

dict:

a = dict(A=1, Z=-1)
a = {'A': 1, 'Z': -1}
a = dict(zip(['A', 'Z'], [1, -1]))
a = dict([('A', 1), ('Z', -1)])
a = dict({'Z': -1, 'A': 1})

del a['Z'] # delete key 'Z'

a['B'] = 2 # add key B and value 2

'B' in a # True

a.clear()

a.keys()

a.values()

a.items()

List/Set Comprehension

Instead of below:

square = []

for n in range(10):
  square.append(n * 2)

do below:

[n * 2 for n in range(10)]

Set comprehension is similar:

do below:

{n * 2 for n in range(10)}

Nested comprehension:

items = ['AB']

[(items[i], items[j]) for i in range(len(items) for j in range(len(items))]

#=>[(A, A), (A, B), (B, B)]

[[col for col in range(5)] for row in range(5)]

#=>[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]

Filtering comprehension:

[n for n in range(10) if n % 2 == 0] 

Map, Zip, Filter

list(map(lambda x: x, range(3)))

#=> [0, 1, 2]

list(map(lambda * x: x, range(3), 'abc'))

#=> [(0, 'a'), (1, 'b'), (2, 'c')]

list(zip(['a', 'b'], [1, 2]))

#=> [('a', 1), ('b', 2)]

list(filter(None, [1, 0, 3, 4]))

#=> [1, 3, 4] ; None implies identitfy function, all values except False (0) is returned

IterTools

Checkout python docs for more. https://docs.python.org/2/library/itertools.html

from itertools import permutations

print(list(permutations('ABC')))

#=> [('A', 'B', 'C'), ('A', 'C', 'B'), ('B', 'A', 'C'), ('B', 'C', 'A'), ('C', 'A', 'B'), ('C', 'B', 'A')]

Generators

Generator functions - they are similar to functions but instead of returning value, they yield which allows them to suspend and resume state between each call.

Generator expressions - they are similar to list comprehensions but instead of returning list, they return an object that produces results one by one.

def get_squares(n):
  for x in range(n):
    yield x ** 2

squares = get_squares(3)
print(next(squares)) # print 0
print(next(sqaures)) # print 1
print(next(sqaures)) # print 4

def counter(start=0):
  n = start
  while True:
    result = yield n
    if result == 'Q':
      break
    n += 1
    
c = counter()
print(next(c)) # 0
print(next(c)) # 1
print(c.send('Q')) # throws StopIteration

#=> generator expression

cubes_gen = (k ** 3 for k in range(10)) # this is a generator expression

#=> (k ** 3) above can be replaced with any type of lambda or def function

Conditional

if income < 1000:
 #do something
elif income < 2000:
 #do something else
else:
 #do entirely different thing
#ternary operator
discount = 25 if order_total > 101 else 0

Looping

for number in [1, 2, 3]:
 print number
 
 
for key in dict:
  # keys printed in arbitrary order
  print dict[key]

while loop:

reminders = []
while n > 0:
 remainder = n % 2
 remainders.append(remainder)
 n //= 2

remainders = remainders[::-1]
print(remainders)

for else:

if for loop is not exited via break then it will go to else clause

class DriverException(Exception):
 pass

people = [('Arun', 3), ('Kirk', 9)]

for person, age in people:
 if age >= 18:
  break
else:
 raise DriverException('Driver not found.')
 

Iterators

Any class that defines __iter__() and __getitem__() method can be used as iterators. Iterator is an object capable of returning its value one at a time.

Functions

def func(a, b, c):
 print(a, b, c)

func(a=1, c=3, b=2)
func(1, 3, 3)

def func2(a=10):
 print a

func2()
func2(11)

variable positional arguments

#can be used to pass variable number of positional argument

def min(*args):
 # args is a tuple now
 if args:
  mn = args[0]
  for value in args[1:]:
   if value < mn:
    mn = value
  print mn
  
min(1, 3, 4, -1)

values = (1, 3, 4, -1)
min(*values) # unpacking the tuple to pass it as separate params

variable keyword argument

similar to variable positional argument but uses ** syntax and collects the parameters in a dict

def func(**kwargs):
 print kwargs
 
 func(a=1, b=10)
 func(**dict(a=1, b=10))

Avoid mutable defaults arguments

Return multiple values possible

Anonymous function (lambda)

lambda x: x
lambda _: print 'hi'

Decorators

A pattern to add extra functionality to a function in a DRY manner

from time import sleep, time
from functools import wraps

def measure(func):
 @wraps(func)
 def wrapper(*args, **kwargs):
  t = time()
  func(*args, **kwargs)
  print(func.__name__, 'took:', time() - t)
 return wrapper
 
@measure
def f(sleep_time=0.1):
 """I'm a dog and I love sleeping!"""
 sleep(sleep_time)
  
f(sleep_time=0.3)
print(f.__name__, ':', f.__doc__)

Decorator factory passes arguments to decorator to modify its behavior dynamically

Class

class Book:
 pass
 
#Ebook extends Book
class EBook(Book):
 pass
 
class EBook(Book):
 def __init__(self, title, format):
  Book.__init__(self, title)
  self.format = format

Advanced (when required) - google or refer to the 'Learning Python' book

static methods class methods private and name mangling property decorator operator overloading multiple inheritance custom iterator

Exceptions

try:
 # some code
except Exception1:
 # react to Exception1
except (Exception1, Exception2):
 # react to Exception1 and Exception2
except Exception3:
 # react to Exception3

Typing

from typing import <types>

variable_name : type_name

# function param
def func1(x: type1) -> type2:
 pass

Testing

poor man's unit testing of module

if __name__ == '__main__':
 funcToTest()

Debugging

print statments

inspect tracebacks

pdb - python debugger

Verifying python script for syntax errors

# From here - https://stackoverflow.com/a/8437583
$ python -m py_compile your_script.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment