Python
Python is a dynamically-typed, interpreted programming language. It has gained widespread use due to its resemblance to pseudo-code and numerous libraries.
Toolchain
Python Package Managers (pip, uv)
Pip Installs Packages (pip):
- most widely used package manager
- Comes pre-installed with Python >3.4
- Installs packages from the Python Package Index (PyPI)
- Usage:
pip install package_name
virtualenv
- tool for creating isolated Python environments
- Allows managing of dependencies for projects separately
- Usage:
virtualenv env_nameandsource env_name/bin/activate(activate virtenv)
pipenv
- Combines
pipandvirtualenv - Uses a Pipfile to specify dependencies and a Pipfile.lock for version locking.
- Usage:
pipenv install package_nameandpipenv shell(Activate virtenv)
uv
- Fast single-binary Python package manager and resolver written in Rust
- Drop-in replacement for
pip,pip-tools,virtualenv - Handles virtual environments natively
- unified CLI for tasks like
uv pip install,uv venv, oruv python - Manages projects with a
pyproject.tomlfile uvx(alias foruv tool run) for executing scripts in isolated environment
Compiling Python (Cython, PyPy)
CPython
- Standard interpreter that can compile python to bytecode
- Runs python line-by-line via the Python Virtual Machine (PVM)
- To compile Python to bytecode:
python -m py_compile source.py - Compiled bytecode lands in the
__pycache__directory. - To execute it from the command line:
python -m source - Python by default is not compiled to an .exe or JIT-compiled to machine code.
- However, there are tools to compile python code.
Cython:
- translates Python code to C/C++ code
- supports calling C functions and declaring C types
PyPy
- Python implementation with a JIT compiler.
- Runtime optimisations, fully language compliant
- Can run most Python code, except for CPython extensions
- PyPy's meta-tracing toolchain is called RPython.
- Uses meta-tracing: interpreter as input and a tracing JIT compiler as output
Type Checking in Python (mypy, ty)
Python supports type hinting since version 3.5:
import typing # primitive type hints def add(a: int, b: int) -> int: return a + b x : int = add(4,5) print(x) # type hints for lists (or tuples, dicts) def get_floats(input : list[float]) -> list[float]: floats : list[float] = [3.4, 2.8, 2.5, 3.9] result = [input[i] + floats[i] for i in range(len(input))] return result print(get_floats([3.5,2.8,3.1])) # union type hints (allow more than one type) def sum_ab(a: int | float, b: int | float) -> int | float: return a + b
Python will not check the types by default. Instead, the types can be statically
checked before running the program by a tool like mypy or ty.
Concepts
Fundamentals
Object:
- Everything in Python is an object
- Including integers, strings, lists, functions, classes and class instances
Attributes:
- An attribute is a value associated with an object
- Instance Attributes are specific to an instance of a class.
- Class Attributes are shared among all instances (static variables)
- Module Attributes are defined at the top level
Syntax
my_list = [1, 2, 3] # declaring list syntax my_dict = {'key': 'value'} # declaring dict syntax # unpack/unwrap operator def add(a, b, c): return a + b + c iterables = [1,2,3] print(add(*iterables)) # same as add(1,2,3) # list comprehensions squares = [x**2 for x in range(4)] # = [0,1,4,9] # slicing sub_list = squares[1:3] # = [1,4] add = lambda x, y: x + y # lambda functions name = "Alice" # normal string greeting = f"Hello, {name}!" # formatted string (f-string)
# imports import math # import module from datetime import datetime # import specific function/class import module as alias # import module with alias from module import * # import all names from a module # if else if x > 0: # conditional elif x < 0: # else if condition else: # else statement def my_function(): # function definition return 42 # return value pass # null operation (placeholder) class MyClass: # class definition # loops for i in range(5): # for loop for _ in range(n): # for loop with unused n while x > 0: # while loop break # exit loop continue # skip to next iteration # exceptions try: # Start of try block # ... except ZeroDivisionError: # Handle specific exception # ... finally: # runs no matter what # ... raise Exception("Err") # raise exception with open('file.txt', 'r') as file: # scoped resource management global x # declare global variable nonlocal y # declare non-local variable in nested function assert x == 4 # assert statement # async async def my_coroutine(): # define asynchronous function await some_async_function() # await asynchronous call async with some_async_context_manager: # async scoped resource manager # ... del x # Delete a variable or object # generators yield value # yield value from generator function yield from another_generator() # Yield all values from another generator if __name__ == "__main__": # check if script is run directly
Decorators
def my_decorator(func): def wrapper(): print("Decorator start.") func() print("Decorator end.") return wrapper @my_decorator def say_hello(): print("Decorated Function") say_hello()
Generators
A generator is a special type of iterator that allows iteration through a
sequence of values. Each time the yield statement of a generator is executed,
the function's state is saved, and it can be resumed later.
def fibonacci(n): a, b = 0, 1 for _ in range(n): yield a a, b = b, a + b fib_gen = fibonacci(4) # get generator object for number in fib_gen: # using the generator print(number)
Exceptions
try: numerator = 10 denominator = 0 result = numerator / denominator except ZeroDivisionError: print("Error: Cannot divide by zero.") else: print("Result:", result) finally: print("Execution completed.") # runs no matter what
Built-In Functions
len() # Returns length (number of items) of object type() # Returns type of object. # data structures list() tuple() set() dict() # math max() min() sum() abs() round() pow(base, exp) divmod(a, b) complex(real, imag) # create complex number # operations zip() # Combines elements from multiple iterables into tuples. map() # Apply function to iterable and return map filter() # Construct iterator from elements of an iterable for which a function returns true. all() # Return True if all elements of an iterable are true any() # Returns True if any element of an iterable is true. If the iterable is empty, returns False. # attributes getattr(obj, name) # retrieve attribute from object hasattr(obj, name) # check if object has specified attribute delattr(obj, name) # delete attribute from object setattr(obj, name, val) # set attribute on object property() # create property attribute # special attributes __doc__ # attribute that stores a docstring __loader__ # attribute for the module loader object __name__ # attribute that stores name of module __package__ # attribute that stores package name of module __spec__ # attribute that stores module's import specification # interpreter compile(src, file, mode) # compile source code into code object eval(expr) # evaluate python expression from string exec(object) # execute python code dynamically exit() # exit interpreter quit() # exit interpreter breakpoint() # drop into the debugger at the call site