Python References
By the Syncfusion DevTutorials team · Last updated
A lookup page for the whole course: one table per topic, from data types and operators to files, class relationships and threads.
You have reached the end of the course. Twenty-six pages, and nobody remembers all of it.
Nor should they. What an experienced programmer actually keeps in their head is a map: there is a method that does this, and it is on strings. The exact spelling is looked up — every day, by everybody.
This page is that lookup. One table per topic, in the order you met them, with a runnable cell wherever seeing the answer beats reading about it.
Here is the whole course in one small program — read it and you will meet most of what you have learnt, working together:
The whole course in one program
from dataclasses import dataclass
@dataclass
class Result:
name: str
subject: str
mark: int
@property
def grade(self):
return "pass" if self.mark >= 35 else "fail"
results = [
Result("Asha", "Maths", 78),
Result("Ravi", "Science", 85),
Result("Meera", "English", 30),
]
for result in sorted(results, key=lambda r: r.mark, reverse=True):
print(f"{result.name:<8}{result.subject:<10}{result.mark:>4} {result.grade}")
passed = [r for r in results if r.grade == "pass"]
print(f"\n{len(passed)} of {len(results)} passed, average {sum(r.mark for r in results) / len(results):.1f}")
Use this page the way you would use a dictionary: not read front to back, but opened at the row you need. Every page title below is a lesson you can go back to.
What You Will Learn
This page is a reference rather than a lesson. It gives you:
- One table per topic, in course order, with the syntax you will look up most
- A runnable cell for the things that are easier seen than described
- The traps worth remembering, collected from every page in one place
By the end of this page, you will be able to find any piece of Python syntax from the whole course in one place, and know the handful of traps that are worth keeping in your head rather than looking up.
Data Types
Here is every type you met, side by side:
| Type | Example | Mutable | Notes |
|---|---|---|---|
int | 78 | — | No size limit |
float | 78.5 | — | Not exact: 0.1 + 0.2 != 0.3 |
complex | 3 + 4j | — | j, not i |
bool | True | — | A kind of int: True == 1 |
str | "Asha" | No | Every method returns a new string |
list | [78, 85] | Yes | Ordered, duplicates allowed |
tuple | (78, 85) | No | The comma makes it, not the brackets |
set | {78, 85} | Yes | No duplicates, no order |
dict | {"Asha": 78} | Yes | Keys must be hashable |
NoneType | None | — | Compare with is, never == |
Checking and converting
value = "78"
print(type(value), isinstance(value, str))
print(int(value), float(value), bool(value))
print(int(78.9), str(78), list("Asha"))
print(bool(""), bool(0), bool([]), bool("0"))
That last line is the one to remember: empty things are false, and "0" is a non-empty string, so it is true.
Keywords
Keywords are reserved words that Python uses as part of the language itself and cannot normally be used as variable names.
Every keyword in the language
import keyword
print(len(keyword.kwlist))
print(keyword.kwlist)
print(keyword.softkwlist)
print(keyword.iskeyword("class"), keyword.iskeyword("classroom"))
Soft keywords — match, case, _, type — are only keywords in their own context, so a variable called match is still allowed.
Operators
Here are the groups, and then the ones that behave unexpectedly:
| Group | Operators |
|---|---|
| Arithmetic | + - * / // % ** |
| Comparison | == != > < >= <= |
| Assignment | = += -= *= /= //= %= **= |
| Logical | and or not |
| Identity | is is not |
| Membership | in not in |
| Bitwise | & | ^ ~ << >> |
| Walrus | := |
The ones that surprise people
print(7 / 2, 7 // 2, 7 % 2, 2 ** 10)
print(-7 // 2)
print(0.1 + 0.2, 0.1 + 0.2 == 0.3)
print(round(0.1 + 0.2, 2) == 0.3)
print("a" in "Asha", 78 in [78, 85])
print(True + True)
-7 // 2 is -4, not -3: floor division rounds down, not towards zero.
Conditional Statements
if condition:
...
elif other_condition:
...
else:
...
value = a if condition else b
match command:
case "add":
...
case "remove" | "delete":
...
case _:
...
In a match, case _ must come last and a bare name as a case matches everything. Both of the tempting mistakes here — putting case _ first, or a bare name in the middle — are hard SyntaxErrors, which is the one mercy of this feature.
Loops
Here are the forms, and what each is for:
| Form | Use |
|---|---|
for item in things: | Walk through a collection |
for i in range(5): | Repeat a fixed number of times |
for i, item in enumerate(things): | Position and item together |
for a, b in zip(xs, ys): | Two collections side by side |
while condition: | Repeat until something changes |
break | Leave the loop now |
continue | Skip to the next turn |
else: on a loop | Runs only if no break happened |
range, enumerate and zip
print(list(range(5)), list(range(2, 10, 3)), list(range(5, 0, -1)))
names = ["Asha", "Ravi"]
marks = [78, 85]
for position, name in enumerate(names, start=1):
print(position, name)
for name, mark in zip(names, marks):
print(name, mark)
for mark in marks:
if mark > 90:
break
else:
print("No mark above 90 — the else ran")
Functions
def name(positional, default=1, *args, keyword_only, **kwargs) -> int:
"""What it does."""
return value
lambda x: x * 2
Here is what the pieces mean:
| Thing | Meaning |
|---|---|
*args | The extra positional arguments, as a tuple |
**kwargs | The extra keyword arguments, as a dictionary |
global x | Assign to a module-level name |
nonlocal x | Assign to the enclosing function's name |
| LEGB | Local, Enclosing, Global, Built-in — the search order |
Never write def add(item, basket=[]). The default list is created once, when the function is defined, and every call that leaves it out shares that same list. Use basket=None and build it inside.
The mutable default, shown
def bad(item, basket=[]):
basket.append(item)
return basket
def good(item, basket=None):
basket = [] if basket is None else basket
basket.append(item)
return basket
print(bad("Asha"), bad("Ravi"))
print(good("Asha"), good("Ravi"))
Modules and Packages
Modules and packages are how Python code is organised and reused across files.
import math
import math as m
from math import sqrt
from math import sqrt as root
from math import * # avoid
if __name__ == "__main__":
main()
A module is a .py file. A package is a folder of modules, usually with an __init__.py. __name__ is "__main__" when the file is run directly, and the module's own name when it is imported — which is what the guard above tests.
Array
The array module, and why a list is usually better
from array import array
marks = array("i", [78, 85, 60])
print(marks, marks.typecode, marks.itemsize)
marks.append(72)
marks.insert(0, 90)
print(marks.tolist(), marks.index(85), sum(marks))
try:
marks.append("ninety")
except TypeError as error:
print("TypeError:", error)
An array holds one type only, which is its point and its limitation. For everyday work, use a list.
String Methods
Here is the full toolkit, grouped by job:
| Group | Methods |
|---|---|
| Case | upper lower title capitalize swapcase casefold |
| Search | find rfind index count startswith endswith |
| Check | isdigit isalpha isalnum isspace isupper islower istitle |
| Change | replace strip lstrip rstrip removeprefix removesuffix |
| Split and join | split rsplit splitlines partition join |
| Pad | ljust rjust center zfill |
The ones used daily
line = " Asha,Maths,78 "
print(repr(line.strip()))
print(line.strip().split(","))
print("-".join(["Asha", "Maths", "78"]))
print("Asha".ljust(10, ".") + "78".rjust(5))
print("asha".title(), "ASHA".lower())
print("78".isdigit(), "78.5".isdigit())
Remember that strings are immutable: every one of those returns a new string and leaves the original alone.
String Formatting
Four ways, and the one to use
name, mark = "Asha", 78.456
print("%s scored %.1f" % (name, mark))
print("{} scored {:.1f}".format(name, mark))
print(f"{name} scored {mark:.1f}")
print(f"{name=}, {mark=}")
print(f"{name:<10}|{mark:>8.2f}|{mark:^10.0f}|")
print(f"{1234567:,} and {0.256:.1%}")
Here is what each spec means:
| Spec | Meaning |
|---|---|
:<10 :>10 :^10 | Left, right, centre in 10 spaces |
:.2f | Two decimal places |
:, | Thousands separator |
:.1% | As a percentage |
{name=} | Prints the expression and its value |
Date and Time
Fixed dates, so the answer is the same every time
from datetime import date, time, datetime, timedelta
exam = date(2026, 3, 15)
print(exam, exam.year, exam.strftime("%d %B %Y"), exam.weekday())
bell = time(9, 30)
print(bell, bell.hour)
start = datetime(2026, 3, 15, 9, 30)
print(start.strftime("%d/%m/%Y %H:%M"))
print(datetime.strptime("15/03/2026", "%d/%m/%Y").date())
print(exam + timedelta(days=30))
print((date(2026, 4, 14) - exam).days)
Here is the code for each part of a date:
| Code | Means |
|---|---|
%d %m %Y | Day, month, four-digit year |
%B %b | Month name, short month name |
%H %M %S | Hour (24), minute, second |
%A %a | Weekday name, short weekday |
date.today() and datetime.now() give a different answer every run — useful in a program, awkward in an example.
Classes and Objects
class Student:
school = "Greenfield" # class attribute, shared
def __init__(self, name, mark):
self.name = name # instance attribute
self._mark = mark # by convention, internal
self.__secret = "hidden" # name-mangled
def describe(self): # instance method
return f"{self.name}: {self._mark}"
def __str__(self):
return self.describe()
Here is which magic method answers which operation:
| Magic method | Called by |
|---|---|
__init__ | Creating the object |
__str__ | print() and str() |
__repr__ | The shell, and repr() |
__len__ | len() |
__eq__ | == |
__lt__ | < and sorted() |
__add__ | + |
__getitem__ | thing[0] |
__contains__ | in |
__call__ | thing() |
Class and Static Methods
Python supports three kinds of methods, each used for a different purpose.
Three kinds of method
class Student:
school = "Greenfield"
def __init__(self, name, mark):
self.name = name
self.mark = mark
def describe(self):
return f"{self.name}: {self.mark}"
@classmethod
def from_text(cls, text):
name, mark = text.split(",")
return cls(name, int(mark))
@staticmethod
def passed(mark):
return mark >= 35
asha = Student.from_text("Asha,78")
print(asha.describe())
print(Student.passed(20), Student.passed(78))
print(Student.school, asha.school)
- An instance method takes
self— it works on one object. - A class method takes
cls— it usually builds one, which is whyfrom_textexists. - A static method takes neither — it is a plain function kept with the class because it belongs there.
Inheritance, Polymorphism, Abstraction and Encapsulation
All four in one example
from abc import ABC, abstractmethod
class Person(ABC):
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@abstractmethod
def role(self):
...
def describe(self):
return f"{self.name} is a {self.role()}"
class Student(Person):
def role(self):
return "student"
class Teacher(Person):
def __init__(self, name, subject):
super().__init__(name)
self.subject = subject
def role(self):
return f"{self.subject} teacher"
for person in [Student("Asha"), Teacher("Mrs Rao", "Maths")]:
print(person.describe())
try:
Person("Nobody")
except TypeError as error:
print("TypeError:", error)
Here are the four ideas, side by side:
| Idea | What it means | How it is written |
|---|---|---|
| Inheritance | A child is a kind of its parent | class Student(Person) |
| Polymorphism | One call, the right version runs | Overriding role() |
| Abstraction | What, not how; the base refuses to be built | ABC and @abstractmethod |
| Encapsulation | The inside is reached through a door you control | _name and @property |
Both ABC and @abstractmethod are needed. With only one of them, the class can still be created and nothing complains.
Collections
Here are the four, side by side:
| Written | Ordered | Changeable | Duplicates | |
|---|---|---|---|---|
| List | [1, 2] | Yes | Yes | Yes |
| Tuple | (1, 2) | Yes | No | Yes |
| Set | {1, 2} | No | Yes | No |
| Dictionary | {"a": 1} | Yes | Yes | Keys, no |
One job done four ways
marks = [78, 85, 60, 78]
print(sorted(marks), len(marks), sum(marks), max(marks))
print(tuple(marks), set(marks))
print({name: mark for name, mark in zip(["Asha", "Ravi"], [78, 85])})
by_name = {"Asha": 78, "Ravi": 85}
print(by_name.get("Meera", 0), list(by_name.items()))
print({"Asha", "Ravi"} & {"Ravi", "Meera"}, {"Asha", "Ravi"} | {"Meera"})
Exception Handling
try:
risky()
except ValueError as error:
...
except (TypeError, KeyError):
...
else:
... # only if nothing was raised
finally:
... # always
raise ValueError("message")
raise NewError("message") from error
class SchoolError(Exception):
pass
Here is which error you get for which mistake:
| Exception | Raised when |
|---|---|
NameError | A name was never defined |
TypeError | Wrong kind of thing |
ValueError | Right kind, impossible value |
ZeroDivisionError | Divided by zero |
IndexError | Position past the end |
KeyError | Key not in the dictionary |
AttributeError | No such method or attribute |
ImportError | That name is not in the module |
ModuleNotFoundError | No such module |
FileNotFoundError | No such file |
The first matching except wins, so a general type above a specific one makes the specific block unreachable — and Python will not warn you. Most specific first, most general last.
File Handling
Here is what each mode does — the two w rows are the ones to read twice:
| Mode | Opens for | If it does not exist | If it does |
|---|---|---|---|
r | Reading | FileNotFoundError | Reads it |
w | Writing | Creates it | Empties it |
a | Appending | Creates it | Adds at the end |
x | Creating | Creates it | FileExistsError |
r+ | Read and write | FileNotFoundError | Keeps it |
w+ | Write and read | Creates it | Empties it |
a+ | Append and read | Creates it | Adds at the end |
b | Added to any: bytes, not text |
Write, read, append
with open("ref_marks.txt", "w") as sheet:
sheet.write("Asha,78\n")
with open("ref_marks.txt", "a") as sheet:
sheet.write("Ravi,85\n")
with open("ref_marks.txt") as sheet:
print(sheet.read())
with open("ref_marks.txt") as sheet:
print(sheet.readlines())
Always use with. It closes the file even if something raises — and an unclosed file can still be empty on disk.
Aggregation and Composition
Here are the two has-a relationships, side by side:
| Aggregation | Composition | |
|---|---|---|
| The part is | Made outside, passed in | Built inside |
| Can be shared | Yes | No |
| When the whole goes | The part stays | The part goes |
| Example | A classroom and its teacher | A classroom and its desks |
class Classroom:
def __init__(self, label, teacher, desk_count):
self.teacher = teacher # aggregation
self.desks = [Desk(n) for n in range(desk_count)] # composition
Multithreading
These are the threading pieces worth remembering after the lesson.
import threading
worker = threading.Thread(target=fetch, args=("Asha",), daemon=False)
worker.start()
worker.join()
lock = threading.Lock()
with lock:
total += 1
Here are the pieces and their jobs:
| Piece | For |
|---|---|
Thread | One thread |
start() / join() | Begin it / wait for it |
Lock | One thread at a time |
Event | A flag one thread sets, another waits for |
current_thread() | The thread running this line |
ThreadPoolExecutor | What you should actually use |
Threads help with waiting, not with arithmetic — Python's global interpreter lock sees to that. And the browser running this page cannot start one at all, which is why that page is mostly code to read.
When you cannot remember a method, ask Python rather than searching. dir("") lists everything a string can do, and help(str.strip) explains one of them. Those two work in any Python anywhere, including this page.
Asking Python instead of searching
print([name for name in dir(str) if name.startswith("r")])
print(len([name for name in dir(list) if not name.startswith("_")]))
print([name for name in dir(dict) if not name.startswith("_")])
Common mistakes
Before moving on, here are some of the mistakes from the whole course, collected in one place.
Each row is one mistake. The middle column is what you will actually see on screen.
| Mistake | What you see | Why it happens | Fix |
|---|---|---|---|
0.1 + 0.2 == 0.3 | False | Floats are binary approximations | round(..., 2), or math.isclose |
-7 // 2 expected to be -3 | -4 | Floor division rounds down | int(-7 / 2) to round towards zero |
(78) meant as a tuple | An int | The comma makes a tuple | (78,) |
basket=[] as a default | Every call shares one list | Defaults are made once | basket=None |
if name == None | Works, but wrongly for odd types | None is one object | if name is None |
| Changing a list while looping it | Items skipped | The positions shift | Loop over a copy |
except Exception above except ValueError | The specific block never runs | First match wins | Specific first |
Opening with w to add | The file is emptied | w truncates | Use a |
from module import * | Names appear from nowhere | Everything was imported | Import what you need |
| A lambda given a name | Tracebacks say <lambda> | It was created without a name | Use def |
Thread(target=fetch()) | Runs immediately, on this thread | The brackets called it | target=fetch |
self left out of a method | TypeError about arguments | The object is passed first | def method(self): |
What to Remember
- Nobody remembers all of this. Knowing that a thing exists is the skill; the spelling is a lookup.
dir(thing)lists what an object can do, andhelp(thing.method)explains one. No internet needed.- Empty things are false:
"",0,[],{},None."0"is not empty, so it is true. - Floats are approximations. Compare them with
round()ormath.isclose, never with==. - Strings and tuples cannot be changed; lists, sets and dictionaries can.
- A list method changes in place and returns
None; the built-in function returns a new object. iscompares identity,==compares value.Nonealways takesis.- A mutable default argument is created once and shared for ever.
- The first matching
exceptwins, so go specific to general. - Opening a file with
wempties it. Always usewith. - Inheritance is is-a; aggregation and composition are both has-a.
- Threads help with waiting, not with arithmetic.
- When you are stuck, the error message is usually telling you the answer. Read the last line first.
Next: You have finished the course