Basics

Last edited

Python programs are executed by an interpreter, the core of the interpreter is a text-based application that can be started by typing python.

When you use Python interactively, the variable _ holds the result of the last operation

Primitives, Variables, and Expressions

Types

42               # int
4.2              # float
'forty-two'      # str
True             # bool

Variable is a name that refers to a value

x = 42

An expression is a combination of primitives, names, and operators that produces a value

2 + 3 * 4

binary

x << y # Left shift
x >> y # Right shift
x & y  # Bitwise and
x | y  # Bitwise or
x ^ y  #  Bitwise xor (exclusive or)
~x     # Bitwise negation
nodes = "10100101"
res = 0b00000000
for bit in nodes:
    res <<= 1 # shift one
    res |= int(bit)

print(f"decimal: {res} ")
print(f"hexa: {res:0x}, {hex(res)}")
print(f"oct: {res:o}, {oct(res)}")
print(f"binary: {res:b}, {bin(res)}")

You can perform these on any variable it is easier to visualize if you prefix with 0b to show the binary representation.

format()

These are the same, just a different interface to call the same protocol

format(x, '0.2f')
f"{x:0.2f}"

File Input and Output

opening and closing

These two are the same, just with uses the python data model to call the open and defer the close for you.

with open('data.txt') as file:
    for line in file:
        print(line, end='') 

file = open('data.txt')
for line in file:
    print(line, end='')
file.close()

reading chunks

Use the read() pethod to cl

with open('data.txt') as file:
    while (chunk := file.read(10000)): # number of characters to read
        print(chunk, end='')

with open('data.txt') as file:
    while (chunk := file.readline(10)): # number of characters to read
        print(chunk, end='')

Data structures

lists

Defining an empty list

# same result
[]     # more idiomatic
list() # typically used to convert data to a list

tuples

a = ()         # 0-tuple (empty tuple)
b = (item,)    # 1-tuple (note the trailing comma)

sets

define an empty set

set()

operators

a = t | s      # Union {'MSFT', 'CAT', 'HPE', 'AA', 'IBM'}
b = t & s      # Intersection {'IBM', 'MSFT'}
c = t - s      # Difference { 'CAT', 'HPE' }
d = s - t      # Difference { 'AA' }
e = t ^ s      # Symmetric difference { 'CAT', 'HPE', 'AA' }

t.add('DIS')                   # Add a single item
s.update({'JJ', 'GE', 'ACME'}) # Adds multiple items to s

t.remove('IBM')    # Remove 'IBM' or raise KeyError if absent.
s.discard('SCOX')  # Remove 'SCOX' if it exists.

dictionaries

defining

{}        # more idiomatic
dict()    # better used to convert to a dict

remove an element of a dictonary

del prices['GOOG']

Exceptions

try-finally

Sometimes there are actions that must be performed no matter what happens. For this, use try-finally.

This is effectively defer in Go.

try:
    doSomething() # possibly could raise an exception
finally:
    cleanUp()

This can also be done through the with statement automatically

with something: # "try"
    ...

# "finally" on exit of block

simple cli arg parsing

import sys
if len(sys.argv) != 2:
    raise SystemExit(f'Usage: {sys.argv[0]} filename')

print(sys.argv[1])

Program termination

This is how you should exit

raise SystemExit()                      # Exit with no error message
raise SystemExit("Something is wrong")  # Exit with error

Inhertiance and Composition

Inhertiance

class Stack:
    STACK_NAME = "test"
    def __init__(self):
        self._items = [ ]

    def push(self, item):
        self._items.append(item)

    def pop(self):
        return self._items.pop()

Say we have a class called Stack and we wanted to to add new method but leave the base Stack class alone.

class NumericStack(Stack): # Inhert all the methods Stack has (3)
    def push(self, item):  # Override the push method
        if not isinstance(item, (int, float)):
            raise TypeError('Expected an int or float')
        super().push(item) # invoke the inherted classes' push method

Composition

What if we instead wanted to just use the stact in our class and invoke it’s methods through a sort of wrapper

class Calculator:
    def __init__(self):
        self._stack = Stack()

    def push(self, item):
        self._stack.push(item)

    def pop(self):
        return self._stack.pop()

    def add(self):
        self.push(self.pop() + self.pop())

Stack as an internal implementation detail. This is called composition, the push(), pop() delegate to the internal stack