Skip to main content

1 Python Basic

Functions​

  • functions without a return statement return None
  • default value: The default value is evaluated only once, unless it is a mutable object such as a list, dictionary, or instances of most classes
  • keyword arguments must follow positional arguments
## General
i = 5
def f(arg=i):
print(arg)

i = 6
f() # 5

## Mutable object
def f(a, L=[]):
L.append(a)
return L

print(f(1)) # [1]
print(f(2)) # [1,2]
print(f(3)) # [1,2,3]

# positional: *name, keyword: **name
def cheeseshop(kind, *arguments, **keywords):
# arguments receives a tuple, keywords receives a dictionary
print("-- Do you have any", kind, "?")
for arg in arguments:
print(arg)
for kw in keywords:
print(kw, ":", keywords[kw])

Scope​

Python has only function scope, no block scope

if a > 3:
choice = "pears"
print(choice) # pears

local vs global variable

only read from global variable, never modify it

choice = "zombie"
def choose_menu():
# choice += "!"
# UnboundLocalError: local variable 'choice' referenced before assignment
return choice + "!"

choice = choose_menu()
print(choice) # zombie!

Unpacking argument lists​

nums = [3, 6]
list(range(*nums)) # * to unpack the arguments out of a list or tuple->[3, 4, 5]
d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
parrot(**d) # ** deliver keyword arguments

lambda​

lambda parameter_list : expression

Function Annotations​

def input(__prompt: object = "") -> str: ...

Class​

Constructor​

python allow only one constructor but multiple inheritance

class Complex(Base1,Base2,Base3): # Inheritance
def __init__(self, realpart, imagpart):
self.r = realpart
self.i = imagpart

Class and instance variables​

class Dog:

kind = 'canine' # class variable shared by all instances
def __init__(self, name):
self.name = name # instance variable unique to each instance

d = Dog('Fido')
e = Dog('Buddy')
print(d.kind) # 'canine'
print(e.kind) # 'canine'
print(d.name) # 'Fido'
print(e.name) # 'Buddy'

Class and Static Method​

A class method can access or modify the class state while a static method can’t access or modify it. They both bound to the class and not the object of the class.

class C(object):
@classmethod
def fun(cls, arg1, arg2, ...):
@staticmethod
def func(arg1, arg2, ...):

Packages​

# absolute imports
import sound.effects.echo
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
# relative imports
from .subpackage1.module5 import function2
from ..filters import equalizer
# naming imports
from sound.effects import echo
echo.echofilter(input, output, delay=0.7, atten=4)

Iterable​

Any classes you define with an __iter__() method or with a __getitem__() method that implements sequence semantics are Iterable

graph LR; SequenceTypes-->Iterable; list-->SequenceTypes; Tuple-->SequenceTypes; Range-->SequenceTypes; dict-->MappingTypes; MappingTypes-->Iterable;

the for statement calls __iter()__ on the container object.

__iter()__returns an iterator object that defines the method __next__() which accesses elements in the container one at a time. When there are no more elements, __next__() raises a StopIteration exception which tells the for loop to terminate.

Generators​

Generators are a simple and powerful tool for creating iterators. However, unlike lists, iterator object generated by Generator does not store their contents in memory.

yield: Each time next() is called on it, the generator resumes where it left off (it remembers all the data values and which statement was last executed).

## Tradition
def csv_reader(file_name):
file = open(file_name)
result = file.read().split("\n")
return result

## Generators
def csv_reader(file_name):
for row in open(file_name, "r"):
yield row
## Generator expression
# csv_gen = row for row in open("some_csv.txt","r")

csv_gen = csv_reader("some_csv.txt")

Common Sequence Operations​

s and t are sequences of the same type, n, i, j and k are integers and x is an arbitrary object that meets any type and value restrictions imposed by s

OperationNotes
x in s
x not in s
s.count(x)
s + tconcatenation, range excluded
s * n or n * srepeat reference, range excluded
s[i]index
s[i:j:k]slice of s from i to j with step k
len(s)The argument may be a sequence (such as a string, bytes, tuple, list, or range) or a collection (such as a dictionary, set, or frozen set).
min(s)/max(s)
sum(s[, start])
any(s) / all(s)(__iterable: Iterable[object]) -> bool
enumerate(s[, start])returns tuple
zip(s, t)*iterables(tuple) -> an iterator of tuple

20230428161659

lists = [[2]] * 3
lists[0].append(3)
print(lists) # [[2, 3], [2, 3], [2, 3]]

#Chaining comparison

# Double comparison
if 0< i < 10: ...
# Multiple comparison
if all([a>10, i<1, y>20]): ...
# zip parameter must be tuple
matrix = [
[1, 2, 3],
[4, 5, 6]
]
transposed = [list(col) for col in zip(*matrix)]

Immutable Sequence Types​

  • int, float, complex, bool, str, tuple
  • support hash()

Mutable Sequence Types​

OperationNotes
s[i] = x
s[i:j:k] = t
s.append(x)
s.pop() or s.pop(i)retrieves the item at i and also removes it from s
s.insert(i, x)
s.copy()creates a shallow copy of s
s.extend(t) / s += t
s *= n
s.remove(x)
s.reverse()
reversed(s)
sorted(s[, key])

Data Types​

Numbers​

  • Division (/) always returns a float. To do floor division and get an integer result you can use the // operator
  • use the ** operator to calculate powers

Strings​

str is immutable, but it implement all of the common sequence operations

Two ways of formating

print(f'The value of pi is approximately {math.pi:1.3f}.')
print('The value of pi is approximately {:1.3f}'.format(math.pi))
# positional and keyword arguments
print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred',other='Georg'))
table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
print('Jack: {Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}'.format(**table)) # Jack: 4098; Sjoerd: 4127; Dcab: 8637678

List​

List is mutable

More:

# check empty
a = []
if a:
print("List has elements")
else:
print("List is empty!")

list.sort(*, key=None, reverse=False)

lst = [('Ann','20','400'), ('Scott','40','500'), ('Bean','10','450')]
lst.sort(key=lambda x:x[1])

# use cmp_to_key
from functools import cmp_to_key
lists = [1,23,2,134,51,213,12,33]
lists.sort(key=cmp_to_key(lambda x,y:x-y))

Tuple​

tuple is immutable

Tuples may be constructed in a number of ways:

  • Using a pair of parentheses to denote the empty tuple: ()
  • Using a trailing comma for a singleton tuple: a, or (a,)
  • Separating items with commas: a, b, c or (a, b, c)
  • Using the tuple() built-in: tuple() or tuple(iterable)

Range​

range is immutable

Dict​

dict is mutable. dict doesn't create missing key using the default value.

a = dict(one=1, two=2, three=3)
b = {'one': 1, 'two': 2, 'three': 3}
c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
d = dict([('two', 2), ('one', 1), ('three', 3)])
e = dict({'three': 3, 'one': 1, 'two': 2})
f = dict({'one': 1, 'three': 3}, two=2)
print(a == b == c == d == e == f) # true

Collections​

from collections import deque, defaultdict, Counter

deque​

Double-ended queue. append, appendleft, pop, and popleft are O(1). Prefer deque to list.pop(0) for BFS.

OperationNotes
deque(iterable)create deque; optional initial elements
q.append(x)add to right, O(1)
q.appendleft(x)add to left, O(1)
q.pop()remove and return rightmost, O(1)
q.popleft()remove and return leftmost, O(1)
q[0] / q[-1]peek at first/last; raises IndexError when empty
# BFS: each node is added and removed at most once
q = deque([start])
visited = {start}
while q:
node = q.popleft()
for nxt in graph[node]:
if nxt not in visited:
visited.add(nxt)
q.append(nxt)

defaultdict​

When a missing key is read with d[key], create a value using the default factory. d.get(key) does NOT create one.

OperationNotes
defaultdict(int)missing value is 0; frequency counting
defaultdict(list)missing value is []; adjacency list / grouping
defaultdict(set)missing value is set(); unique neighbors
d[key]create missing key using the factory
d = defaultdict(list)
d.get(10) # None; 10 is still absent
d[10] # []; key 10 is now present

Counter​

Counter is a dict subclass for frequency counting. Missing keys return 0 without inserting them.

OperationNotes
Counter(iterable)count each element
c[x]frequency, 0 if absent
c.update(iterable)add counts
c.subtract(iterable)subtract counts; can become negative
c.most_common(k)list of k most frequent (element, count) pairs
c.total()sum of all counts
c.elements()iterate positive-count elements repeated by count
c1 + c2 / c1 - c2add/subtract counts; keep only positive results
c = Counter('abaca')  # Counter({'a': 3, 'b': 1, 'c': 1})
c['z'] # 0
c.most_common(1) # [('a', 3)]
c.update('bb') # 'b' count becomes 3

# anagram check
Counter('listen') == Counter('silent') # True

heapq: Heap / Priority Queue​

heapq maintains a min-heap inside a list. The first element heap[0] is smallest, but the whole list is NOT sorted.

import heapq
OperationNotes
heapq.heapify(a)convert list to min-heap in O(n), in place
heapq.heappush(h, x)push item, O(log n)
heapq.heappop(h)remove smallest, O(log n)
h[0]peek smallest, O(1)
heapq.heappushpop(h, x)push then pop smallest, optimized
heapq.heapreplace(h, x)pop smallest then push; heap must be nonempty
heapq.nlargest(k, iterable)get k largest elements
heapq.nsmallest(k, iterable)get k smallest elements
h = [5, 1, 3]
heapq.heapify(h)
heapq.heappush(h, 2)
heapq.heappop(h) # 1

# Max-heap technique: negate numbers
h = []
for x in [3, 1, 5]:
heapq.heappush(h, -x)
-heapq.heappop(h) # 5

# Priority with a tie-breaker
h = []
heapq.heappush(h, (2, 'taskB'))
heapq.heappush(h, (1, 'taskA'))
heapq.heappop(h) # (1, 'taskA')

Control Flow and Loops​

## ifelse
if x < y:
print("x is less than y")
elif x > y:
print("x is greater than y")
else:
print("x is equal to y")
## Switch
# Only the first pattern that matches gets executed
match status:
case 400:
return "Bad request"
case 401| 403 |404:
return "Not allowed"
case 404:
return "Not found"
case 418:
return "I'm a teapot"
case _:
return "Something's wrong with the internet"

Exceptions​

try:
result = x / y
except ZeroDivisionError:
print("division by zero!")
finally:
print("executing finally clause")