Python - ttulka/programming GitHub Wiki

Data Types

type(exp) type of the expression. bin(number) binary representation of number as string. int('0b101', 2) # 5 or int('5') # 5 parses number. str(123) parses as string.

Fundamental Data Types

  • int
  • float
  • bool
  • str
  • list
  • dict
  • tuple
  • set
  • complex

Numbers

print(2 ** 3) # 2^3 == 8

print(7 / 3) # 2.3333333333333335
print(7 // 3) # 5 div 3 == 1 

Strings

  • Strings are immutable.
  • len(string) lenght of string.
s = 'string'
s = "string"
s = '''multiple
line
string
'''
s = 'string' + 123 # Error
s = 'string' + str(123)
weather = "It's \"kind of\" sunny\n"
'abc' * 3   # 'abcabcabc'
s = ' '.join(['a','b','c']) # 'a b c'
contains = 'ab' in 'abc'  # True
String slicing

string[start:stop:stepover] creates slice from string.

'0123'[0]    # '0' (string)
'0123'[1:3]  # '12'
'0123'[1:]   # '123'
'0123'[:2]   # '01'

'012345'[1:5:2]  # '13'
'012345'[::3]    # '03'

'012345'[-2]     # '4'
'012345'[-2:6]   # '45'
'012345'[2:-2]   # '23'
'012345'[::-1]   # '543210'
'012345'[::-2]   # '531'
Formatted strings
print('User {} is {}.'.format('John', 33))

print('User {1} is {0}.'.format(33, 'John'))

print('User {name} is {age}.'.format(name='John', age=33))
name = 'John'
age = 33

print(f'User {name} is {age}.')

print(f'Name is {len(name)} chars long.')

Booleans

  • True or False
  • not(bool) negates.
bool(1)   # True
bool(0)   # False
bool(None)# False
bool(123) # True
bool('ab')# True
bool('0') # True
bool(0.0) # False
bool(0.01)# True
bool([])  # False
bool([0]) # True
bool('')  # False
2 - True  # 1
2 - False # 2
Truthy and Falsey
if 5:
    print('5 is truthy')

All values are considered "truthy" except for the following, which are "falsy":

  • False
  • None
  • 0
  • 0.0
  • 0j
  • Decimal(0)
  • Fraction(0, 1)
  • [] - empty list
  • {} - empty dict
  • () - empty tuple
  • '' - empty str
  • b'' - empty bytes
  • set() - empty set
  • empty range, like range(0)
  • objects for which
    • obj.__bool__() returns False
    • obj.__len__() returns 0
== vs is Operator
  • == checks for equality
  • is checks for identity (in memory)
True == 1       # True
'' == 1         # False
'1' == 1        # False
10 == 10.0      # True
[1,2] == [1,2]  # True
True is 1       # False
'' is 1         # False
'1' is 1        # False
10 is 10.0      # False
[1,2] is [1,2]  # False
1 is 1          # True
'1' is '1'      # True

Lists

  • Lists are mutable.
  • len(list) lenght of list.
li = [1, 2, 3]
li = ['a', 'b', 'c']
li = [1, 2, True, 'abc']

matrix = [1], [2, 3], [4](/ttulka/programming/wiki/1],-[2,-3],-[4)
matrix[1][0] = 300
  • li = list[:] or li = list.copy() copy of list.
  • li = list(range(3)) creates list [0,1,2].
  • li = list(range(2,5)) creates list [2,3,4].
Adding into list
  • list.append(obj) appends object into list.
  • list.insert(index, obj) inserts obj into index.
  • list.extend([obj1, obj2, ...]) appends objects.
Removing from list
  • list.pop() pops last item out of list.
  • list.remove(obj) removes object.
  • list.clear() removes all.
Retriving list items
  • list.index(obj, [start, [stop]]) finds object in list.
  • obj in list returns True if object is in list.
  • list.count(obj) occurences of object in list.
  • list.sort() sorts list.
  • li = sorted(list) returns sorted copy of list.
  • list.reverse() reverses list.
List slicing
  • list[start:stop:stepover] creates slice from list.
[0,1,2,3,4,5][1:5:2]  # [1, 3]
[0,1,2,3,4,5][2:-2]   # [2, 3]
List unpacking
a,b,c = [1,2,3] # a==1, b==2, c==3

a,b,*other = [1,2,3,4]  # a==1, b==2, c==[3,4]

a,*other,b = [1,2,3,4]  # a==1, other==[2,3], b==4

Dictionaries

  • Only hashable immutable keys are allowed.
di = {True: 1, 123: [], (1,2): 'x', 'abc': {}}

di['abc']['a'] = 1
di # {True: 1, 123: [], (1,2): 'x', 'abc': {'a': 1}}
  • di.get('key') gets value for key or None.
  • di.get('key', default) get value of default.
  • key in dict True if key exists in dictionary.
  • di.keys() keys of dictionary.
  • di.values() values of dictionary.
  • di.items() tuples of dictionary.
  • di.clear() clears disctionary.
  • di.copy() copy of disctionary.
  • di.pop(key) removes item with key.
  • di.update({key:val}) modifies or add item.

Tuples

  • Immutable lists.
tu = (1,2,3,4,5)
tu[0]   # 1
tu[1:3] # (2,3)
a,b,*x = tu     # a==1, b==2, x==[3,4,5] (list)

tu = (2,)   # single element
  • tu.index(obj) index of object.
  • len(tu) length of tuple.

Sets

  • Unique objects with no order.
  • Doesn't support indexing.
se = {1,2,3,3,3,3}      # {1,2,3}
se = set([1,2,3,3,3])   # {1,2,3}
  • se.add(val) add value.
  • len(se) length of set.
  • se.copy() copy of set.
  • se.clear() clears set.
  • se.discart(val) removes value from set if exists.
  • val in se True if value exists in set.
  • se1.difference(se2) set with differences.
  • se1.intersection(se2) or se1 & se2 intersection set.
  • se1.union(se2) or se1 | se2 union set.
  • se1.issubset(se2) True if se1 is subset of se2.
  • se1.issuperset(se2) True if se1 is superset of se2.

Classes (Custom Types)

Specialized Data Types

None

Variables

  • Letters, Numbers, Underscores
  • Case-sensitive
  • Must start with lowercase or underscore.
  • snake_case
a,b,c = 1,2,3

x = 1
y = 2
x,y = y,x

print(x, y) # 2 1

Conditions

if condition:
    command
    command
    ...
elif condition:
    command
    command
    ...
elif condition:
    command
    command
    ...
else:
    command
    command
    ...
# Short Circuiting applied for both

if cond1 and cond2:
    command

if cond1 or cond2:
    command

Ternary Operator

  • if_true if condition else if_false
allowed = True
msg = 'is allowed' if allowed else 'not allowed'
msg # 'is allowed'

For Loops

for i in iterable:
    command
    pass
    break
    continue
    ...
print(i)    # i still available

Iterables

  • List, tuple, set, string (as chars), dictionary (as keys), ...
  • Range
for num in range(0, 100):
    print('number:', num)    # 100 times

for num in range(0, 100, 2): # only even numbers
    print('number:', num)    # 50 times

for num in range(100, 0, -1): # 100 to 1
    print('number:', num)     # 100 times
  • enumerate(iterable) creates enumeration from iterable:
for index,val in enumerate([1,2,3]):
    print(index, val)

Comprehensions (List, Set, Dictionary)

li = [char for char in 'hello']     # ['h','e','l','l','o']
li = [num for num in range(0,5)]    # [0, 1, 2, 3, 4]
li = [num**2 for num in range(0,5)] # [0, 1, 4, 9, 16]
li = [n**2 for n in range(0,5) if n%2==0] # [0, 4, 16]

se = {n**2 for n in range(0,5) if n%2==0} # {0, 4, 16}

di = {'a': 1, 'b': 2}
di = {k:v**2 for k,v in di.items() if v%2==0}  # {'b': 4}
li = [1, 1, 2, 3, 4, 3]

list({x for x in li if li.count(x) > 1})  # [1,3]

While Loops

while condition:
    command
    pass
    break
    continue
    ...
else:        # executes only when no break
    command
    command
    ...

Functions

def myfunc(param1=defval1, param2=defval2, ...):
    '''
    Docstring hints the users about this func.
    '''
    command
    command
    pass
    def myfunc2(...):
        ...
    ...
    return val

myfunc(val1, val2, ...)
myfunc(param2=val2, param1=val1)

myfunc_ref = myfunc
myfunc_ref(...)     # calls the referenced function

*args and **kwargs

  • func(params, *args, default params, **kwargs)
def myfunc(*args):
    print(args)
    return sum(args)

myfunc(1, 2, 3)         # 6
# prints tuple (1,2,3)
def myfunc(**kwargs):
    print(kwargs)
    return sum(kwargs.values())

myfunc(var1=1, var2=2)  # 4
# prints dict {'var1':1, 'var2':2}
def myfunc(first, *args, i='hi', **kwargs):
    print(first)
    print(args)
    print(i)
    print(kwargs)

myfunc('abc',1, 2, var1=True, var2=False)
# prints:
# abc
# (1, 2)
# hi
# {'var1': True, 'var2': False}

Scope

  1. Local
  2. Parent local
  3. Global
  4. Build-in functions
a = 1

if True:
    x = 1

def myfn():
    global a
    a = 2
    x = 2
    y = 2
    z = 2
    def myfn2():
        nonlocal z
        z = 3
    myfn2()
    return z

z = myfn()

print(a)    # 2
print(x)    # 1
# print(y)  # Error
print(z)    # 3

Higher Order Functions

def run_func(fn):   # HOC
    fn()

def hello():
    print('hello')

run_func(hello)  # hello

Decorators

def my_decorater(func):
    def wrap_func():
        print('start')
        func()
        print('end')
    return wrap_func

@my_decorater
def hello():
    print('hello')

hello()  # start hello end
def my_param_decorater(func):
    def wrap_func(*args, **kwargs):
        func(*args, **kwargs)
    return wrap_func

@my_param_decorater
def hello(name):
    print(f'hello, {name}!')

hello('abc')
from time import time
def performance(fn):
    def wrap(*args, **kwargs):
        t1 = time()
        res = fn(*args, **kwargs)
        t2 = time()
        print(f'took {t2-t1} ms')
        return res
    return wrap

@performance
def do_something():
    print('working...')

do_something()

Built-in Functions

Object

  • getattr(object, name[, default]) - gets object attribute.
  • hasattr(object, name) - True if object has attribute.
  • setattr(object, name, value) - sets attribute.
  • delattr(object, name) - deletes attribute from object.
  • hash(object) - integer hash value of object (if has any).
  • id(object) - unique integer object identity.
  • vars([object]) - attributes as dictionary.

Number

  • abs(num) - absolute value.
  • max(iterable, *[, key, default]) - max value.
  • min(iterable, *[, key, default]) - min value.
  • sum(iterable, /, start=0) - sum value.
  • pow(base, exp[, mod]) - powers base to exp.
  • round(num[, ndigits]) - rouned number.

String

  • format(value[, format_spec]) - formats value.
  • ascii(object) - sting with escaped non-ASCII literals.
  • bin(num) - string binary representation starting with 0b.
  • hex(x) - string hexadecimal starting with 0x.
  • oct(x) - string octal starting with 0o.
  • chr(int) - string for Unicode character.
  • ord(c) - integer Unicode for character.
  • repr(object) - object as string.

Iterable

  • len(seq) - length of sequence (string, bytes, tuple, list, range).
  • enumerate(iterable, start=0) - enumerates object.
  • range(stop), range(start, stop[, step])
  • next(iterator[, default]) - next value.
  • all(iterable) - True if all items are truthy.
  • any(iterable) - True if any item is truthy.
  • filter(predicatefn, iterable) - iterator from iterable matching predicate.
  • map(func, iterable, ...) - maps all items in iterable.
  • sorted(iterable, *, key=None, reverse=False) - sorted list.
  • reversed(seq) - reversed iterator.
  • slice(stop), slice(start, stop[, step]) - slice object.
  • zip(*iterables) - zip object (product).

Function

  • callable(object) - True if object is callable.

Classes

  • type(object), type(name, bases, dict) - type of object.
  • isinstance(object, classinfo) - True if object is instance of class.
  • issubclass(class, classinfo) - True if object is subclass of class.
  • super([type[, object-or-type]]) - proxy object.

File

  • open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) - opens file.

Other

  • print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False) - prints.
  • input([prompt]) - prompts user unput.
  • dir([object]) - list of valid names in local scope, or object attributes.
  • eval(expression[, globals[, locals]]) - evaluates expression.
  • exec(object[, globals[, locals]]) - executes Python code.
  • help([object]) - prints help info with docstring.

Pure Functins

  • map, filter, zip and reduce.
def multiply_10(item):
    return item * 10

def is_odd(num):
    return num % 2 != 0  

li = [1, 2, 3]
li2 = list(
    map(multiply_10, 
        filter(is_odd, li)))
 
print(li2)  # [10, 30]

zi1 = list(zip(li, li2))
zi2 = list(zip(li2, li))

print(zi1)  # [(1, 10), (2, 30)]
print(zi2)  # [(10, 1), (30, 2)]

def sum(a, c):
    return a + c

from functools import reduce

r = reduce(sum, li, 0)

print(r)   # 6

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

Lambda Expressions

One-time annonynous functions.

(lambda x: x + 1)(2)    # 3

add_one = lambda x: x + 1
add_one(2)  # 3

high_ord_func = lambda x, func: x + func(x)
high_ord_func(2, lambda x: x * x)   # 6

(lambda x, y, z=3: x + y + z)(1, 2)     # 6
(lambda x, y, z=3: x + y + z)(1, y=2)   # 6
map(lambda i: i * 2, [1,2,3])   # [2,4,6]

reduce(lambda a, c: a + c, [1,2,3], 0)  # 6
a = [(0,2), (4,3), (2,1)]

# sorting by the second key
a.sort(key=lambda x: x[1])

print(a)    # [(2,1), (0,2), (4,3)]

Objects and Classes

  • No access modificators.
  • By convention use _ for private members.
class MyObject:
    
    classobj = 1    # static member

    def __init__(self, name):
        self.name = name
        MyObject.classobj = 2

    def mymethod(self, hello):
        print(f'{hello}, {self.name}!')

    @classmethod
    def staticmethod1(cls, text):
        classobj = 3
        return cls(text)

    @staticmethod
    def staticmethod2(val):
        classobj = val

myobj = MyObject('abc')
myobj.mymethod('Hello')    # Hello, abc!

myobj = MyObject.staticmethod1('cde')
myobj.mymethod('Hello')    # Hello, cde!

myobj = MyObject.staticmethod2(4)

Inheritance

class SuperClass:
    def __init__(self, name):
        self.name = name

    def mymethod1(self):
        print('super', self.name)

class SubClass(SuperClass):
    def __init__(self, name):
        super().__init__(name)
        # SuperClass.__init__(self, name)

    def mymethod2(self):
        print('sub', self.name)
        super().mymethod1()
        # SuperClass.mymethod1(self)

sub = SubClass('my')
sub.mymethod1() # super my
sub.mymethod2() # sub my super my

isinstance(sub, SubClass)   # true
isinstance(sub, SuperClass) # true
isinstance(sub, object)     # true

Multiple Inheritance

Multiple inheritance is possible in Python.

class Super1:
    def __init__(self, name, s1):
        self.name = name
        self.s1 = s1
    def method1(self):
        print(self.name, self.s1)

class Super2:
    def __init__(self, name, s2):
        self.name = name
        self.s2 = s2
    def method2(self):
        print(self.name, self.s2)

class Sub(Super1, Super2):
    def __init__(self, name, s1, s2):
        Super1.__init__(self, name, s1)
        Super2.__init__(self, name, s2)

sub = Sub('my','o1','o2')
sub.method1()   # my o1
sub.method2()   # my o2

Method Resolution Order (MRO)

Based on Depth First Search.

#     A
#    / \   
#   C   B  X
#    \ /  /
#     D---

class X:
    name = 'x'

class A:
    name = 'a'

class B(A):
    pass

class C(A):
    name = 'c'

class D(C, B, X):
    pass

D.mro() # D, C, B, A, X, object
D.name  # 'c'

Dunder Methods

Special object methods __method__.

str(myobj) == myobj.__str__();
class MyClass:
    def __str__(self):
        return 'my object'

my = MyClass()
str(my)     # 'my object'
class MyClass:
    def __call__(self):
        print('calling...')

my = MyClass()
my()     # calling...
class MyClass:
    def __getitem__(self, i):
        return f'{i}. item'

my = MyClass()
my[2]     # '2. item'
my['xyz'] # 'xyz. item'

Error Handling

try:
    raise Exception('boom')
except (ValueError, IndexError) as e:
    print(f'Error occured: {e}')
except TypeError:
    print('Type error occured')
except:
    print('Error occured')
else:
    print('Everything fine')
finally:
    print('Done')

Generators

  • For streaming values.
  • Iterable.
  • Don't hold items in memory (reuse the same memory place for current item).
  • Using range and yield.
def my_generator(n):
    for i in range(n):
        yield i

for i in my_generator(100):
    print(i)    # 0 - 99

g = my_generator(100)
next(g)  # 0
next(g)  # 1
def fibonacci_generator(n):
    prev = 0
    next = 1
    for _ in range(n+1):
        yield prev
        prev, next = next, prev+next
        
for i in fibonacci_generator(7):
    print(i)    # 0 1 1 2 3 5 8 13

Modules

  • __pycache__ directory contains compiled imports.
  • __init__.py file must be in every Python package.
  • __name__ is always __main__ for file being run.
  • __name__ is filename for files being imported.
# common/utility.py

print(__name__)    # common/utility.py 

def multiply(a, b):
    return a * b

def divide(a, b):
    return a / b
# main.py

print(__name__)    # __main__

import common.utility

common.utility.multiply(2, 3)

from common import utility

utility.multiply(2, 3)

from common.utility import multiply, divide

multiply(2, 3)
divide(6, 2)

from common.utility import *

multiply(2, 3)
divide(6, 2)

pip

TBD

Debugging

import pdb

def add(a, b):
    pdb.set_trace()  # pauses here
    return a + b

add(1, 'abc')

File I/O

f = open('test.txt')

content = f.read()  # content of file
content = f.read()  # nothing 
f.seek(0)
content = f.read()  # content of file
f.seek(0)

line = f.readline() # next line
f.seek(0)

lines = f.readlines()   # list of lines

f.close()
try:
    with open('test.txt', mode='r+') as f:  # closes automatically
        bytes_written = f.write('hello')    # 5
        print(f.read())
except FileNotFoundError as e:
    print('file does not exist')
    raise e
except IOError as e:
    print(f'IO Error: {e}'')
    raise except

Regular Expressions

import re

pattern = re.compile('this')
string = 'search in this text'

a = patter.match(string)    # True
b = pattern.search(string)  # 'this'
c = pattern.findall(string)
c.group()   # ['this']

Testing

# main.py

def add(a, b):
    return a + b

# test.py

import unittest
import main

class TestMain(unittest.TestCase):
    def setUp(self):
        print('runs before each test')

    def test_adding(self):
        test_a = 2
        test_b = 3
        result = main.add(test_a, test_b)
        self.assertEqual(result, 5)

    def test_wrong_param(self):
        test_a = 2
        test_b = 'abc'
        result = main.add(test_a, test_b)
        self.assertIsInstance(result, TypeError)
    
    def tearDown(self):
        print('run after every test')

unittest.main()     # run all tests

References