Python Syntax Notes

Core Python only. Every syntax: topic name, one line, then the code.

BeginnerStart here

Basics

Comments

Notes ignored by Python.

# single line
"""multi-line string, also used as docstring"""

Variables

Names bound to values; no type declaration needed.

x = 10
name = "Ann"

Multiple assignment & swap

Assign several names at once or swap values.

a, b = 1, 2
a = b = 0
a, b = b, a

Unpacking

Split a sequence into names; * collects the rest.

first, *rest = [1, 2, 3]
*init, last = [1, 2, 3]

Indentation

Blocks are defined by 4-space indentation, not braces.

if True:
    print("inside block")

Line continuation

Split long lines with a backslash or brackets.

total = 1 + 2 + \
        3
items = [1,
         2]
a = 1; b = 2   # two statements on one line

Data types

Numbers

Integers, floats and complex numbers.

42   0b101   0o17   0xFF   1_000_000
3.14   1e-3   float("inf")
3 + 4j

Bool and None

Truth values and the "nothing" value.

True   False   None

Type check

Find or test an object's type.

type(x)
isinstance(x, int)
isinstance(x, (int, float))

Type conversion

Convert between types with constructors.

int("5")  float("1.5")  str(5)  bool(0)
list("ab")  tuple([1])  set([1])
chr(65)  ord("A")  hex(255)  bin(5)  oct(8)

Operators

Arithmetic

/ always gives float; // floors.

+  -  *  /  //  %  **

Comparison

Compare values; chaining is allowed.

==  !=  <  >  <=  >=
1 < x < 10

Logical

Combine conditions with words, not symbols.

and   or   not

Identity & membership

Same object? Item inside a collection?

x is None   x is not None
3 in [1, 2, 3]   3 not in L

Bitwise

Operate on the bits of integers.

&  |  ^  ~  <<  >>

Augmented assignment

Update a variable in place.

x += 1   x -= 1   x *= 2   x /= 2   x //= 2   x %= 2   x **= 2

Conditional expression

One-line if/else that returns a value.

y = a if cond else b
v = x or "default"

Strings

Indexing & slicing

Access characters by position; negative counts from the end.

s = "hello"
s[0]  s[-1]  s[1:3]  s[::2]  s[::-1]
s + "x"   s * 3   "e" in s   len(s)

f-strings

Embed expressions and format them inline.

f"{name}"  f"{x:.2f}"  f"{x:>10}"  f"{n:,}"  f"{x!r}"  f"{x=}"
"{} {}".format(1, 2)
"%s %d" % ("a", 1)

Escapes & raw strings

Special characters inside strings.

\n  \t  \\  \'  \"  \xhh  \uXXXX
r"raw\n"   b"bytes"

String methods

Built-in tools to transform and test text.

s.upper() s.lower() s.title() s.strip() s.split(",") ",".join(L)
s.replace("a","b") s.find("x") s.count("a") s.startswith("h") s.endswith("o")
s.isalpha() s.isdigit() s.isalnum() s.center(10) s.zfill(5) s.splitlines()

Collections

List

Ordered, changeable sequence.

l = [1, 2, 3]
l[0]  l[1:]  l.append(4)  l.extend([5])  l.insert(0, 0)
l.remove(2)  l.pop()  l.index(3)  l.count(1)  l.sort()  l.reverse()  del l[0]

Tuple

Ordered, unchangeable sequence.

t = (1, 2)    t = 1,    t = ()

Set

Unordered collection of unique items.

s = {1, 2}   s.add(3)   s.discard(1)
a | b   a & b   a - b   a ^ b

Dictionary

Key-value pairs.

d = {"a": 1, "b": 2}
d["a"]  d["c"] = 3  del d["a"]  "a" in d
d.get("x", 0)  d.keys()  d.values()  d.items()  d.update(o)  d.pop("a")

Control flow

if / elif / else

Run code only when a condition is true.

if x > 0:
    ...
elif x == 0:
    ...
else:
    ...

for loop

Repeat over any iterable.

for i in range(5): ...
for i, v in enumerate(L): ...
for a, b in zip(A, B): ...
for k, v in d.items(): ...

while loop

Repeat while a condition holds.

while cond:
    ...

break, continue, else, pass

Control the loop; else runs if no break happened.

for x in L:
    if a: continue
    if b: break
else:
    ...
pass   # do nothing

Functions

Define & call

Reusable block of code that can return a value.

def add(a, b=2):
    """docstring"""
    return a + b
add(1)   add(1, b=5)

Return multiple values

Return a tuple and unpack it.

def pair(): return 1, 2
x, y = pair()

Lambda

Small anonymous function.

square = lambda n: n * n

Input, output & files

print and input

Show output and read user text.

print("a", "b", sep="-", end="")
name = input("Name: ")

Reading & writing files

with closes the file for you. Modes: r w a x b +.

with open("f.txt", "r", encoding="utf-8") as f:
    data = f.read()      # readline()  readlines()
with open("f.txt", "w") as f:
    f.write("text")

Exceptions (basic)

try / except / else / finally

Handle runtime errors gracefully.

try:
    x = int("a")
except ValueError as e:
    print(e)
else:
    ...      # no error
finally:
    ...      # always runs

raise & assert

Trigger an error yourself or check an assumption.

raise ValueError("bad")
assert x > 0, "must be positive"
IntermediateOOP, functional tools and structure

Comprehensions

List, set, dict, generator

Build collections in one readable line.

[x * 2 for x in range(5) if x % 2]
{x for x in "hello"}
{k: v for k, v in d.items()}
(x * x for x in range(5))
[(a, b) for a in A for b in B]

Functions in depth

*args and **kwargs

Accept any number of positional or keyword arguments.

def f(a, b=2, *args, c, d=4, **kwargs): ...
f(*[1, 2], **{"c": 3})

Positional-only and keyword-only

/ and * restrict how arguments are passed.

def g(a, b, /, c, *, d): ...

Scope: global & nonlocal

Modify variables from an outer scope.

counter = 0
def inc():
    global counter
    counter += 1

def outer():
    n = 0
    def inner():
        nonlocal n
        n += 1
    return inner

Functional built-ins

Process iterables without explicit loops.

map(f, L)  filter(f, L)  sorted(L, key=lambda x: x[1], reverse=True)
any(L)  all(L)  min(L, key=len)  sum(L)  zip(A, B, strict=True)

OOP: classes

Class & object

A class is a blueprint; __init__ sets up each object.

class Animal:
    count = 0                  # class attribute
    def __init__(self, name):
        self.name = name       # instance attribute
        self._prot = 1         # protected by convention
        self.__priv = 2        # name-mangled
    def speak(self):
        return f"{self.name} makes a sound"

a = Animal("Rex")
a.name   a.speak()   Animal.count

Class & static methods

Methods that belong to the class, not the instance.

    @classmethod
    def create(cls, name): return cls(name)
    @staticmethod
    def helper(x): return x * 2

Properties

Getter/setter behaviour behind attribute syntax.

    @property
    def upper(self): return self.name.upper()
    @upper.setter
    def upper(self, v): self.name = v.lower()

String representation

Control how objects print.

    def __repr__(self): return f"Animal({self.name!r})"
    def __str__(self):  return self.name

Attribute helpers

Inspect and change objects dynamically.

hasattr(a, "x")  getattr(a, "x", None)  setattr(a, "x", 1)  delattr(a, "x")
vars(a)  dir(a)  type(a)  a.__class__.__name__

OOP: inheritance & polymorphism

Inheritance

A child class reuses and overrides parent behaviour.

class Dog(Animal):
    def __init__(self, name):
        super().__init__(name)
    def speak(self):               # override
        return f"{self.name} barks"

Multiple inheritance & MRO

Inherit from several classes; MRO decides lookup order.

class Bird(Animal, Flyer): ...
Bird.__mro__

isinstance & issubclass

Check relationships between objects and classes.

isinstance(d, Animal)   issubclass(Dog, Animal)

Abstract classes

Force subclasses to implement certain methods.

from abc import ABC, abstractmethod
class Shape(ABC):
    @abstractmethod
    def area(self): ...

Dataclasses & enums

dataclass

Auto-generates __init__, __repr__, __eq__.

from dataclasses import dataclass, field
@dataclass(frozen=True, order=True, slots=True)
class Point:
    x: int
    y: int = 0
    tags: list = field(default_factory=list)

Enum

A fixed set of named constants.

from enum import Enum, auto
class Color(Enum):
    RED = auto()
    BLUE = 2
Color.RED.name   Color.RED.value   Color(2)

Modules & packages

import

Reuse code from other files and libraries.

import math
import math as m
from math import sqrt, pi
from math import sqrt as s
from . import sibling
from .pkg import name

Main guard & __all__

Run code only when executed directly; control public names.

__all__ = ["public_name"]
if __name__ == "__main__":
    main()

Exceptions (custom & chaining)

Custom exception

Subclass Exception for your own errors.

class AppError(Exception):
    def __init__(self, msg, code):
        super().__init__(msg)
        self.code = code

Chaining & re-raise

Keep the original cause or hide it.

except (TypeError, KeyError) as e:
    raise AppError("failed", 1) from e
except Exception:
    raise
raise ValueError("x") from None

Iterators & generators

Iterator protocol

Any object with __iter__ and __next__.

class Count:
    def __init__(self, n): self.n, self.i = n, 0
    def __iter__(self): return self
    def __next__(self):
        if self.i >= self.n: raise StopIteration
        self.i += 1
        return self.i
it = iter(L)   next(it)   next(it, None)

Generator function

yield produces values lazily, one at a time.

def gen():
    yield 1
    yield 2
    yield from other()

Context managers

with statement

Guarantees setup and cleanup around a block.

with open("a") as a, open("b") as b: ...
with (open("a") as a, open("b") as b): ...   # 3.10+

Custom context manager

Implement __enter__ and __exit__.

class Ctx:
    def __enter__(self): return self
    def __exit__(self, exc_type, exc, tb): return False

Decorators

Function decorator

Wrap a function to add behaviour.

def deco(fn):
    def wrapper(*args, **kwargs):
        return fn(*args, **kwargs)
    return wrapper

@deco
def work(): ...

Decorator with arguments

A factory that returns a decorator.

def repeat(n):
    def d(fn):
        def w(*a, **k):
            for _ in range(n): fn(*a, **k)
        return w
    return d

@repeat(3)
def hi(): ...

match / case

Structural pattern matching (3.10+)

Match values and shapes of data.

match command:
    case "go": ...
    case "stop" | "halt": ...
    case [x, y]: ...
    case [first, *rest]: ...
    case {"type": "a", "v": v}: ...
    case Point(x=0, y=0): ...
    case int() | float() as n if n > 0: ...
    case _: ...
AdvancedObject model, async and metaprogramming

Dunder (magic) methods

Operator overloading

Make your objects work with operators and built-ins.

class Vec:
    def __init__(self, x, y): self.x, self.y = x, y
    def __add__(self, o): return Vec(self.x + o.x, self.y + o.y)
    def __eq__(self, o): return (self.x, self.y) == (o.x, o.y)
    def __hash__(self): return hash((self.x, self.y))
    def __len__(self): return 2
    def __getitem__(self, i): return (self.x, self.y)[i]
    def __call__(self): return "called"

Full list

Special names Python calls for you.

__new__ __init__ __del__ __repr__ __str__ __format__ __bool__ __hash__
__eq__ __ne__ __lt__ __le__ __gt__ __ge__
__add__ __sub__ __mul__ __matmul__ __truediv__ __floordiv__ __mod__ __pow__
__and__ __or__ __xor__ __lshift__ __rshift__ __neg__ __pos__ __abs__ __invert__
__radd__ (r-variants)  __iadd__ (i-variants)
__int__ __float__ __index__ __round__
__len__ __getitem__ __setitem__ __delitem__ __contains__ __iter__ __next__ __reversed__
__missing__ __call__ __enter__ __exit__
__getattr__ __getattribute__ __setattr__ __delattr__ __dir__
__copy__ __deepcopy__ __getstate__ __setstate__ __reduce__
__class_getitem__ __init_subclass__ __match_args__ __slots__

Descriptors & __slots__

Descriptor

An object that customises attribute access on another class.

class Positive:
    def __set_name__(self, owner, name): self.name = "_" + name
    def __get__(self, obj, objtype=None):
        return self if obj is None else getattr(obj, self.name)
    def __set__(self, obj, value):
        if value <= 0: raise ValueError
        setattr(obj, self.name, value)

class Item:
    price = Positive()

__slots__

Fixed attributes, saves memory, no per-instance dict.

class P:
    __slots__ = ("x", "y")

Metaclasses

Custom metaclass

A class whose instances are classes.

class Meta(type):
    def __new__(mcs, name, bases, ns, **kw):
        return super().__new__(mcs, name, bases, ns)
    def __call__(cls, *a, **k):
        return super().__call__(*a, **k)
class A(metaclass=Meta): ...

Dynamic class & hooks

Create classes at runtime; react to subclassing.

Dyn = type("Dyn", (object,), {"x": 1})
class Base:
    def __init_subclass__(cls, **kw): super().__init_subclass__(**kw)
def class_deco(cls): cls.tag = 1; return cls
@class_deco
class B: ...

Async / await

Coroutines

Functions that can pause while waiting.

async def fetch():
    await something()
    return 1

Async iteration & context

Async versions of for, with and comprehensions.

async def agen():
    yield 1
async for x in agen(): ...
async with ctx as c: ...
[x async for x in agen()]

class AC:
    async def __aenter__(self): ...
    async def __aexit__(self, *a): ...
    def __aiter__(self): ...
    async def __anext__(self): ...

Two-way generators

send, throw, close

Generators can receive values and errors.

def acc():
    total = 0
    while True:
        x = yield total
        total += x
g = acc(); next(g)
g.send(5)   g.throw(ValueError)   g.close()
r = yield from sub()   # delegate and capture return

Exception groups (3.11+)

except*

Handle several errors raised together.

try:
    raise ExceptionGroup("many", [ValueError(1), TypeError(2)])
except* ValueError as eg: ...
except* TypeError as eg: ...
e.add_note("extra context")
e.__cause__   e.__context__   e.__traceback__

Type hints & generics

Annotations

Optional hints for tools and readers.

def f(a: list[int], b: dict[str, int] | None = None) -> tuple[int, ...]: ...
from typing import Any, Optional, Union, Callable, Literal, Final
from typing import TypedDict, Protocol, Generic, TypeVar, ClassVar, Self, Annotated

Generics

Write code that works for any type.

T = TypeVar("T")
class Box(Generic[T]): ...
def first[T](xs: list[T]) -> T: ...   # 3.12+
class Stack[T]: ...
type Alias = list[int]                # 3.12+

Dynamic features

eval, exec, introspection

Run and inspect code at runtime.

eval("1 + 2")   exec("x = 1")   compile(src, "f", "exec")
globals()   locals()   id(x)   hash(x)   callable(f)
f.__name__  f.__doc__  f.__annotations__  f.__defaults__
__import__("os")   breakpoint()

Keywords

All reserved words

Names you cannot use as variables.

False None True and as assert async await break class continue def del elif else
except finally for from global if import in is lambda nonlocal not or pass raise
return try while with yield
# soft keywords: match case _ type