Python Notes ============ Print ----- .. code-block:: python print("Hello World") - Can also print a variable: ``print(name)`` - Or print words and a variable: ``print("Hello " + name)`` - Can be used to figure out a type: ``print(type(name))`` - To print a string with an int you must type cast: ``print("Your age is: " + str(age))`` - An easy way to print a string with variables is an f-string: ``print(f"Hello {name} it's {day}")`` - When printing a boolean variable it will return ``True`` or ``False`` - For a print in a loop when you don't want a new line each time, use: ``print(x, end=" ")`` - For a new line use ``\n`` Variables --------- A variable is a container for a value. It behaves as the value that it contains. **Types** - **String**: a series of characters. Ex: ``name = "Greyson"`` - **Int**: a whole number. Ex: ``age = 20`` - **Float**: a decimal number. Ex: ``height = 6.5`` - **Boolean**: ``True`` or ``False``. Ex: ``on = False`` Variables can be added together: .. code-block:: python first_name = "Greyson" last_name = "Trubia" full_name = first_name + last_name Multiple Assignment ~~~~~~~~~~~~~~~~~~~ Assign multiple variables at the same time in one line of code. .. code-block:: python name, age, alive = "Greyson", 20, True # Sets them all to 30 spongebob = patrick = sandy = squidward = 30 String Methods -------------- .. code-block:: python print(len(name)) # length of a string print(name.find("r")) # position of a character within a string print(name.capitalize()) # capitalize the first letter print(name.upper()) # make string all uppercase print(name.lower()) # make string all lowercase print(name.isdigit()) # True/False - is the string a digit print(name.isalpha()) # True/False - is the string alphabetical characters print(name.count("e")) # count how many times "e" appears in the string print(name.replace("e", "a")) # replace "e" with "a" print(name * 3) # print a string multiple times .. note:: **Correction:** ``count()`` needs an argument — the character (or substring) you want to count occurrences of, e.g. ``name.count("e")``. It does not count total characters (that's what ``len()`` is for). Type Casting ------------ Converts the data type of a value to another data type. .. code-block:: python # Temporary change number = "5" # string print(int(number)) # prints the string as an int # Permanent change y = 2.0 # float y = int(y) Useful to perform mathematical operations on numbers contained in a string, or to print a number together with a string. User Input ---------- To ask for user input use ``input()``. .. code-block:: python input("What is your name?") This will ask the user for an input and wait for an entry in the console window, but doesn't store it. .. code-block:: python name = input("What is your name?: ") print("Hello " + name) User input will always be recorded as a string unless you change that: .. code-block:: python age = int(input("How old are you?: ")) # records the input as an int Math Functions -------------- Use ``import math`` to access math functions. Tip: type ``math.`` to see all possible functions. .. code-block:: python import math round(x) # nearest whole number math.ceil(x) # round up math.floor(x) # round down abs(x) # how far the number is from 0 pow(var, n) # raise number to a power math.sqrt(x) # square root of a number max(a, b, c) # find the largest value of variables or numbers min(a, b, c) # find the smallest value of variables or numbers pi = 3.14 print(math.ceil(pi)) .. note:: **Correction:** the round-up function is ``math.ceil()``, not ``math.ciel()``. String Slicing -------------- Creating a substring by extracting elements from another string, using indexing ``[ ]`` or ``slice()``. **Indexing** — ``[start:stop:step]`` .. code-block:: text name = "Joe Smith" J o e S m i t h 0 1 2 3 4 5 6 7 8 .. code-block:: python name = "Joe Smith" first_name = name[0:3] # "Joe" - You can also do ``name[:3]`` to start from the beginning without typing the start index. The same works in reverse — leave the stop field empty and give a start index to slice to the end. - ``step`` is used to display every 2+ letters, starting from the first. - Always include the colons, even if leaving a field blank. - To reverse a string, set the step to ``-1``. **Slice object** — similar to indexing: .. code-block:: python website = "https://google.com" s = slice(8, -4) print(website[s]) # "google" .. note:: **Correction:** the original example used ``slice(7, -4)``, which actually includes the leading ``/`` and prints ``"/google"``. To get just ``"google"`` the start index should be ``8``. If Statements ------------- Do something only *if* something is true, *else* do something else. .. code-block:: python age = int(input("Enter your age: ")) if age >= 18: print("You are now signed up") elif age < 0: print("You haven't been born yet") else: print("You must be 18+ to sign up") **Boolean in an if statement** .. code-block:: python for_sale = True if for_sale: print("It is for sale") No need to write a comparison — the variable itself acts as the condition. .. note:: **Correction:** in Python, booleans are capitalized — ``True`` / ``False``, not ``true`` / ``false``. Example programs referenced: ``calculator.py``, ``converter.py`` (lbs to kg), ``tempconverter.py`` (F to C). Logical Operators ------------------ Evaluate multiple conditions (``or``, ``and``, ``not``). - ``or`` — at least one condition must be true - ``and`` — both conditions must be true - ``not`` — inverts the condition .. code-block:: python if temp > 30 or is_raining: print("Event is cancelled") elif temp > 30 and is_sunny: print("Event is active") elif temp > 30 and not is_sunny: print("It's cloudy") Conditional Expressions ------------------------ A one-line shortcut for the if/else statement. Print or assign one of two values based on a condition: ``X if condition else Y``. .. code-block:: python grade = 85 print("Passed" if grade > 65 else "Failed") a = 6 b = 7 max_num = a if a > b else b min_num = a if a < b else b Example programs referenced: ``gradecheck.py``. String Methods Reference ------------------------- Use ``print(help(str))`` to list all string methods. - ``len(variable)`` — number of characters in a string - ``variable.find(" ")`` — finds the character (e.g. a space) and returns its position - ``variable.rfind("o")`` — finds the *last* occurrence of a character and returns its position; returns ``-1`` if not found - ``variable.capitalize()`` — capitalizes the first letter - ``variable.upper()`` — makes all characters uppercase - ``variable.lower()`` — makes all characters lowercase - ``variable.isdigit()`` — ``True``/``False`` based on whether there are only numbers - ``variable.isalpha()`` — ``True``/``False`` based on whether there are only letters (a space does not count as a letter) - ``variable.count("e")`` — counts how many times that character appears - ``variable.replace("-", " ")`` — replaces all of the first character/string with the second String Indexing ---------------- Indexing = accessing elements of a sequence using ``[ ]`` — ``[start:end:step]``. The start field is inclusive, the end field is exclusive. Leave ``start`` blank to begin at the start, leave ``end`` blank to go to the end. Negative indexes count from the end. .. code-block:: python credit_number = "1234-5678-9012-3456" print(credit_number[0]) # "1" - first number of the sequence print(credit_number[0:4]) # "1234" - first 4 numbers, not the dash print(credit_number[-1]) # "6" - starts from the end print(credit_number[::2]) # every second number, starting from the first print(credit_number[::-1]) # the credit card number backwards Format Specifiers ------------------ Used in an f-string to format a value, based on flags. Multiple flags can be combined without separators. .. code-block:: python price1 = 3.14159 price2 = -987.65 price3 = 1200.34 print(f"price1 is {price1:.2f}") # rounds to 2 decimal places -> 3.14 print(f"price2 is {price2:10}") # pads the value to a minimum width of 10 characters print(f"price3 is {price3:,}") # comma thousands separator -> 1,200.34 print(f"{price1:+,.2f}") # plus sign if positive, comma separator, 2 decimals - ``.f`` — round to that many decimal places (fixed point) - ``:`` — allocate that many spaces (minimum field width) - ``:03`` — allocate that many spaces, zero-padded - ``:<`` — left justify - ``:>`` — right justify - ``:^`` — center align - ``:+`` — use a plus sign to indicate a positive value - ``:=`` — place the sign in the leftmost position - ``: `` — insert a space before positive numbers - ``:,`` — comma separator .. note:: **Correction:** ``{price2:10}`` pads the *value itself* out to a minimum width of 10 characters (numbers are right-justified by default) — it doesn't add 10 literal spaces after the surrounding text. While Loops ----------- While loops execute code *while* some condition remains true. .. code-block:: python food = input("Enter a food you like (q to quit): ") while not food == "q": print(f"you like {food}") food = input("Enter another food you like (q to quit): ") print("Done") There must be a way to exit the loop, or it becomes an infinite loop — ``break`` can be used to escape early. For Loops --------- Execute a block of code a fixed number of times. You can iterate over a range, string, sequence, etc. **Range** — counting to 10 (start is inclusive, stop is exclusive): .. code-block:: python for x in range(1, 11): print(x) Counting backwards: .. code-block:: python for x in reversed(range(1, 11)): # 10, 9, 8 ... 1 print(x) # equivalent alternative for x in range(10, 0, -1): # 10, 9, 8 ... 1 print(x) .. note:: **Correction:** the original notes gave ``range(11, 1, -1)`` as equivalent to ``reversed(range(1, 11))``. It isn't — ``range(11, 1, -1)`` produces 11 down to 2, while ``reversed(range(1, 11))`` produces 10 down to 1. The matching range is ``range(10, 0, -1)``. Adding a step (a third argument counts by that amount): .. code-block:: python for x in range(1, 11, 2): # counts by 2s print(x) Skip a specific value with ``continue``: .. code-block:: python for x in range(1, 21): if x == 13: continue else: print(x) # skips 13, prints every other number End the loop early with ``break``: .. code-block:: python for x in range(1, 21): if x == 13: break else: print(x) # stops when it reaches 13 **Looping over a string:** .. code-block:: python name = "Greyson" for x in name: print(x) # prints each letter on a separate line Collections ----------- A single variable used to store multiple values. - **List** ``[ ]`` — ordered and changeable, allows duplicates - **Set** ``{ }`` — unordered, mutable (you can add/remove items), does not allow duplicates - **Tuple** ``( )`` — ordered and unchangeable, allows duplicates, faster; use in place of a list when you don't need to change anything .. note:: **Correction:** sets *are* mutable — you can add and remove elements from them after creation. It's the individual elements of a set that must be immutable (hashable), not the set itself. To see the functions available for a collection: ``print(dir(fruits))``. To see what a function does: ``print(help(fruits))``. .. code-block:: python fruits = ["apple", "orange", "blueberry"] # list print(fruits[2]) # "blueberry" print(fruits[0:2]) # ["apple", "orange"] print("apple" in fruits) # True/False - search for an item fruits[0] = "pineapple" # change an item by index .. note:: **Correction:** ``fruits[0:2]`` prints ``["apple", "orange"]`` (items at index 0 and 1) — not the whole list. List Functions ~~~~~~~~~~~~~~ .. code-block:: python fruits.append("strawberry") # add to the end of the collection fruits.remove("apple") # remove "apple" fruits.insert(0, "banana") # insert "banana" at the front fruits.sort() # sort the list alphabetically fruits.reverse() # reverse the list fruits.clear() # clear the list fruits.index("apple") # returns the index of "apple" fruits.count("banana") # returns how many times "banana" appears Tuple Functions ~~~~~~~~~~~~~~~~ Tuples are immutable, so they only support these two: .. code-block:: python fruits.index("apple") # returns 0 fruits.count("banana") # returns 1 2D Lists ~~~~~~~~ A list made up of lists. You need at least two 1D lists to build one. .. code-block:: python groceries = [["apple", "orange", "banana"], ["celery", "carrot", "potato"]] # or, using existing list variables groceries = [fruits, vegetables] If you print ``groceries`` it shows both lists on the same line, separated by a comma. Access a specific item by its coordinates: .. code-block:: python print(groceries[0][0]) # first item in the first list Iterate over a 2D list with a nested loop: .. code-block:: python for collection in groceries: for food in collection: print(food) Dictionary ---------- A collection of ``{key: value}`` pairs. Ordered and changeable, no duplicate keys. .. code-block:: python capitals = {"USA": "Washington D.C.", "China": "Beijing"} print(capitals.get("USA")) # "Washington D.C." Check whether a key exists: .. code-block:: python if capitals.get("USA"): print("That item does exist") else: print("That item does not exist") Update an existing item: .. code-block:: python capitals.update({"USA": "New York"}) Remove the last-inserted item: .. code-block:: python capitals.popitem() Clear the dictionary: .. code-block:: python capitals.clear() Get all the keys (or values): .. code-block:: python keys = capitals.keys() for key in capitals.keys(): print(key) # same pattern, but capitals.values() for values Print all keys with their values: .. code-block:: python items = capitals.items() for key, value in capitals.items(): print(f"{key}: {value}") Random ------ Must use ``import random``. .. code-block:: python import random # random number number = random.randint(low, high) # random choice options = ("rock", "paper", "scissors") choice = random.choice(options) # shuffle cards = ["2", "3", "6", "K", "A"] random.shuffle(cards) Functions --------- A block of reusable code. Add ``()`` after the function name to invoke it. .. code-block:: python def name(): # code, indented underneath the function definition pass name() # calling the function With arguments: .. code-block:: python def hi_name(name, age): print(f"Hello {name}! You're {age} years old.") hi_name("Greyson", 20) Return Statement ~~~~~~~~~~~~~~~~~ Ends a function and sends a result back to the caller. .. code-block:: python def add(x, y): z = x + y return z print(add(3, 5)) def create_name(first, last): first = first.capitalize() last = last.capitalize() return first + " " + last full_name = create_name("Greyson", "T") print(full_name) Default Arguments ~~~~~~~~~~~~~~~~~~ A default value for a parameter, used when the argument is omitted. Makes functions more flexible and reduces the number of required arguments. .. code-block:: python def net_price(list_price, discount=0, tax=0.05): return list_price * (1 - discount) * (1 + tax) print(net_price(500)) # discount and tax fall back to defaults print(net_price(500, 0.1)) # discount = 0.1, tax still defaults to 0.05 Keyword Arguments ~~~~~~~~~~~~~~~~~~ An argument preceded by an identifier. Helps readability; order doesn't matter. .. code-block:: python def hello(greeting, title, first, last): print(f"{greeting} {title} {first} {last}") hello(title="Mr.", greeting="Hello", first="Guy", last="Smith") You can mix positional and keyword arguments, but keyword arguments must come after positional ones when calling the function. Arbitrary Arguments ~~~~~~~~~~~~~~~~~~~~ A varying number of arguments. - ``*args`` — packs multiple non-keyword arguments into a tuple - ``**kwargs`` — packs multiple keyword arguments into a dictionary - ``*`` is the unpacking operator .. code-block:: python def add(*args): total = 0 for arg in args: total += arg return total print(add(1, 2, 4)) .. code-block:: python def print_address(**kwargs): for key, value in kwargs.items(): print(f"{key}: {value}") print_address(street="123 fake st.", city="Detroit", state="MI", zip="54321") .. note:: **Correction:** the ``kwargs`` example looped with ``for key in kwargs.items()`` but then referenced an undefined ``value``. Unpack both with ``for key, value in kwargs.items()``. Both together: .. code-block:: python def shipping_label(*args, **kwargs): for arg in args: print(arg, end=" ") print() if "apt" in kwargs: print(f"{kwargs.get('street')} {kwargs.get('apt')}") else: print(f"{kwargs.get('street')}") print(f"{kwargs.get('city')} {kwargs.get('state')} {kwargs.get('zip')} {kwargs.get('country')}") shipping_label("Dr.", "Spongebob", "Squarepants", street="123 Fake St.", city="Detroit", state="MI", zip="54321", country="US") .. note:: **Correction:** the final ``print()`` in the original was missing its closing parenthesis and quote. Iterables --------- An object/collection that can return its elements one at a time so it can be looped over. Examples: list, tuple, set, string, dictionary. .. code-block:: python numbers = [1, 2, 3, 4, 5] for number in numbers: print(number) my_dictionary = {"A": 1, "B": 2} for value in my_dictionary.values(): # values only print(value) for key, value in my_dictionary.items(): # keys and values print(f"{key} = {value}") for key in my_dictionary: # keys only print(key) Membership Operators --------------------- Test whether a value is found in a sequence (string, list, tuple, set, dictionary), using ``in`` and ``not in``. .. code-block:: python word = "APPLE" letter = input("Guess a letter in the secret word: ") if letter in word: print(f"There is a/an {letter} in the word") elif letter not in word: print(f"There is not a/an {letter} in the word") .. code-block:: python students = {"Spongebob", "Patrick", "Sandy"} student = input("Enter the name of a student: ") if student in students: print(f"{student} is a student") else: print(f"{student} is not a student") .. code-block:: python grades = {"Sandy": "A", "Squidward": "B", "Spongebob": "C", "Patrick": "D"} student = input("Enter the name of a student: ") if student in grades: print(f"{student}'s grade is {grades[student]}") else: print(f"{student} was not found") List Comprehension -------------------- A concise way to create lists — more compact and often easier to read than a traditional loop: ``[expression for value in iterable if condition]``. .. code-block:: python doubles = [x * 2 for x in range(1, 11)] print(doubles) # 2, 4, 6, 8 ... 20 .. code-block:: python numbers = [1, -2, 3, -4, 5, -6] positive_nums = [num for num in numbers if num > 0] negative_nums = [num for num in numbers if num < 0] # sort positive and negative numbers into separate lists .. code-block:: python grades = [85, 66, 93, 58, 97, 45] passing = [grade for grade in grades if grade > 65] failing = [grade for grade in grades if grade < 65] .. code-block:: python fruits = ["apple", "orange", "banana", "coconut"] fruits = [fruit.upper() for fruit in fruits] print(fruits) # each item in uppercase fruit_chars = [fruit[0] for fruit in fruits] print(fruit_chars) # first letter of each fruit .. note:: **Correction:** the positive/negative example originally used ``>= 0`` and ``<= 0``, which puts ``0`` in both lists. Using ``> 0`` and ``< 0`` keeps the two lists mutually exclusive. Match-Case Statements (Switch) -------------------------------- An alternative to a long chain of ``elif`` statements — cleaner and more readable. Runs the code for whichever ``case`` matches the value. .. code-block:: python def day_of_week(day): match day: case 1: return "It is Sunday" case 2: return "It is Monday" case 3: return "It is Tuesday" case 4: return "It is Wednesday" case _: return "Not a valid day" print(day_of_week(1)) # "It is Sunday" .. note:: **Correction:** the original call was ``day_of_week("1")`` (a string), which would not match ``case 1`` (an int) and would fall through to ``case _``. Pass the int ``1`` to match correctly. Module ------ A file containing code you want to include in your program. Use ``import`` to include a built-in or your own module — useful for breaking a large program into reusable files. .. code-block:: python print(help("modules")) # list all built-in modules print(help("math")) # functions in a specific module, with descriptions To make a module name shorter: .. code-block:: python import math as m # m can be whatever you want To import a single function: .. code-block:: python from math import pi # instead of 1 * math.pi, you can now use: 1 * pi Creating a Module ~~~~~~~~~~~~~~~~~~ Just make a new Python file — the file name is the module name. Once imported into the main file, its variables and functions carry over. Variable Scope -------------- Where a variable is visible/accessible. Scope resolution order (LEGB): Local → Enclosed → Global → Built-in. - **Local** — a function can see its own variables and any passed to it, but not variables from other functions. - **Enclosed** — a function defined inside another function. - **Global** — defined outside any function; used if a variable isn't defined locally. - **Built-in** — names provided by an imported module/library, used unless overridden by a global, enclosed, or local value of the same name. .. code-block:: python def func1(): print(x) # prints 3 - uses the global variable x def func2(): x = 1 print(x) # prints 1 - the local variable takes precedence x = 3 func1() func2() .. note:: **Correction:** the original example called ``func(1)`` and ``func(2)`` — neither function exists under that name, and neither ``func1`` nor ``func2`` takes an argument. The calls should be ``func1()`` and ``func2()``. ``if __name__ == '__main__':`` -------------------------------- Indicates that a script can either be imported as a module or run standalone. When present, the functions and classes in the module can be reused without the main block automatically executing. Usually placed just before a call to ``main()``. (Example files: ``script1.py``, ``script2.py``.) Object-Oriented Programming ----------------------------- An **object** is a "bundle" of related attributes (variables) and methods (functions). A **class** is the blueprint used to design an object's structure. .. code-block:: python class Car: def __init__(self, model, year, color, for_sale): # constructor self.model = model self.year = year self.color = color self.for_sale = for_sale # methods go inside the class def drive(self): print(f"You drive the {self.model}") def stop(self): print(f"You stop the {self.model}") car1 = Car("Mustang", 2024, "red", False) car2 = Car("Corvette", 2022, "blue", True) print(car1.model) # "Mustang" print(car2.model) # "Corvette" car1.drive() # "You drive the Mustang" (Example files: ``car.py``, ``oop.py``.) Class Variables ~~~~~~~~~~~~~~~~ Shared among all instances of a class. Defined outside the constructor, so all objects created from the class share the same data. .. code-block:: python class Student: class_year = 2030 # shared among all students num_students = 0 def __init__(self, name, age): self.name = name self.age = age Student.num_students += 1 # counts students as you create them Inheritance ~~~~~~~~~~~ Allows a class to inherit attributes/methods from another class — helps code readability. Syntax: ``class Child(Parent):``. .. code-block:: python class Animal: def __init__(self, name): self.name = name self.is_alive = True def eat(self): print(f"{self.name} is eating.") class Dog(Animal): def speak(self): print("Woof") class Cat(Animal): def speak(self): print("Meow") class Mouse(Animal): def speak(self): print("Squeak") .. note:: **Corrections:** Python's keyword is lowercase ``class``, not ``Class`` (fixed throughout this section). Instance methods like ``speak`` also need a ``self`` parameter. Multiple Inheritance ~~~~~~~~~~~~~~~~~~~~~ - **Multiple inheritance** — inheriting from more than one parent class: ``class C(A, B):`` - **Multilevel inheritance** — inheriting from a parent which itself inherits from another parent: ``C(B)`` where ``B(A)`` where ``A`` is the base class. .. code-block:: python class Animal: def __init__(self, name): self.name = name def eat(self): print(f"{self.name} is eating") def sleep(self): print(f"{self.name} is sleeping") class Prey(Animal): def flee(self): print(f"{self.name} is fleeing") class Predator(Animal): def hunt(self): print(f"{self.name} is hunting") class Rabbit(Prey): pass class Hawk(Predator): pass class Fish(Prey, Predator): pass rabbit = Rabbit("Bugz") rabbit.eat() .. note:: **Correction:** empty class bodies (``Rabbit``, ``Hawk``, ``Fish``) need a ``pass`` statement, or Python raises a syntax error. Super() ~~~~~~~ Used in a child class to call a method from the parent class (superclass), extending the inherited method's functionality. If a child method shares a name with a parent method, the child's version overrides it — but both can still be called. .. code-block:: python class Parent: def describe(self): print("Parent description") class Child(Parent): def describe(self): print("Description") # child super().describe() # parent (Example file: ``super.py``.) Polymorphism ~~~~~~~~~~~~ From the Greek "poly" (many) + "morphe" (form) — "to have many forms." Two ways to achieve polymorphism: 1. **Inheritance** — an object can be treated as the same type as its parent class. 2. **Duck typing** — an object just needs to have the necessary attributes/methods, regardless of its actual class.