Python3 Documentation
number
: Replace with a number.*object
: Any number of objects.[, ndigits]
: Anything between[]
is optional.
Run Python Code
Python is an interpreted language. It is not compiled like C.
python hello.py
Skipping the compiling step makes the language easier to use but at the cost of performance.
Print information on the console.
print("hello, world")
answer = "Some Text"
print(f"Your answer is: {answer}") # formatted string (any type)
print("Your answer is: " + answer) # answer must be string
print("Your answer is:", answer) # answer can be any type
print("Same line", end="")
print("!" * 4) # "!!!!
# '' and "" do the same.
Input
Prompt the user for information.
# String Input
name = input("Prompt: ")
number = int(input("Prompt: "))
name = name.strip() # Remove whitespaces from a string
Variables
Python infers the type of variable automatically.
answer = "Some Text"
counter = 0
counter = counter + 1
counter += 1
# Counter++ does not exist in Python
Global Variables
Use the global keyword to modify a global variable while outside its scope.
balance = 0
def deposit(n):
global balance
balance += n
Comments
# Comment
"""
Multi
Line
Comment
"""
Docstring
The documentation for a function.
This can later be used to generate manuals and documentation Some IDEs do so automatically.
def code():
"""
Does something.
"""
...
Type Hints
Type hints are not enforced. These can be read by debuggers, but Python itself allows these types to be violated.
def meow(n: int) -> None: # -> None indicates that the function does not return a value
...
number: int = int(input("Number: "))
Data Types
Data Type Category | Data Types |
---|---|
Text Type | str |
Numeric Types | int , float , complex |
Sequence Types | list , tuple , range |
Mapping Type | dict |
Set Types | set , frozenset |
Boolean Type | bool |
Binary Types | bytes , bytearray , memoryview |
None Type | NoneType |
float
types can overflow, much like C, butint
never does, and instead grows as large as needed to fit a given value.
Type Conversion
int("1") # convert to int
float(2) # convert to float
Data Type Functions
round(5.12) # round a number
round(3.43, 2) # round to the 2nd decimal place
len(list) # length of a list (nº of elements)
Unpack Values
Values can be split using *
. This method works with lists, dictionaries, and tuples.
For dictionaries, *dict
returns key names and **dict
returns the value names.
Unpack can also be used when returning values from functions.
def total(gold, silver, copper):
return gold * 100 + silver * 10 + copper
coins = [100, 50, 25]
print(total(*coins), "Copper coins")
F Strings
A string that executes formatting.
f'Some text: {1+1}' # Executes 1+1 and prints "Some text: 2"
f'{z:.2f}' # Variable z is rounded to the 2nd decimal place.
Ranges
Produce a range of numbers.
range(10) # 1, 2, 3... 10
if 80 <= score < 90:
code...
Lists
Arrays are flexible in Python, unlike C. Elements can be added and removed at runtime.
scores = [72, 73, 33]
scores.append(32)
# scores += [43, 45] # Adds a list to another list
average = sum(scores) / len(scores)
print(f"Average: {average}")
scores[1:] \#Slice the list -> From 1 to the end. (Skips element 0)
scores[1:-1] \#Slice the list -> From 1 to the end. (Skips element 0 and last)
List Comprehension
Create a new list with a function applied to every element of the list.
words = ["This", "is", "CS50"]
uppercased = [word.upper() for word in words]
print(*uppercased)
In this example, every element in words
is uppercased.
This feature is useful to filter items as well:
students = [
{"name": "Trude", "class": "code"},
{"name": "Maxs", "class": "art"},
{"name:" "JCionx", "class": "code"},
]
codeStudents = [
student["name"] for student in students if student["class"] == "code"
]
Filter Function
Similar code, but for a more functional oriented programming approach.
def is_class(s):
return s["class"] == "code"
coders = filter(is_class, students)
Sets
Similar to a list, but can only contain unique items.
values = set(1, 1, 1, 2)
print(values) # 1, 2
Dictionaries
A list, but instead of using an index, uses keywords.
students = {
"Key1": "Value",
"Key2": "Value",
"Key3": "Value",
}
print(students["Key1"])
Loop over Dictionary
for student in students:
print(student) # Iterates over keys.
print(students[student]) # Iterates over values.
Dictionary Comprehension
Filter dictionaries.
students = ["Trude", "Maxs", "JCionx"]
# Classic for
coders = []
for student in students:
coders.append({"name": student, "class": "code"})
# List comprehension (3 dicts in a list)
coders = [{"name": student, "class": "code"} for student in students]
# Dict comprehension (1 dict with name: class for all 3)
coders = {student: "code" for student in students}
Hashtable
table = [
{"Key1": "Value", "Key2": "Value", "Key3": "Value"},
{"Key1": "Value", "Key2": "Value", "Key3": "Value"},
{"Key1": "Value", "Key2": "Value", "Key3": "Value"},
{"Key1": "Value", "Key2": "Value"},
]
print(table[0]["Key2"])
for tab in table:
print(tab["Key1"]) # Print all Key1 values.
Conditions
IF
if x < y:
print("x is less than y")
elif x > y:
print("x is greater than y")
else:
print("x is not less than y")
if test in numbers:
code...
()
are optional in the condition.
:=
Operator
Syntax sugar to integrate an assignment operator with an IF statement.
Without it
matches = 1 == 1
if matches:
print(matches) # True
With it
if matches := 1 == 1:
print(matches) # True
Loops
While
while True:
print("meow")
i = 0
while i < 3:
print("meow")
i += 1
For
Loop through an Array
for _ in [0, 1, 2]:
print("Hello World.")
# _ throws away the value (no variable).
Loop through a Range
for i in range(3):
print("Loops from 0 - 3")
Loop through an Array, Using Its Value as the Index
students = ["one", "two", "three"]
for student in students:
print(student)
Enumerate
Iterate over a sequence, and get the current value and index.
students = ["Trude", "Maxs", "JCionx"]
for i, student in enumerate(students):
print(i + 1, student)
Map
Execute a function on every element of a list.
Takes two arguments:
- Name of a function
- Data structure to apply the function on
words = ["This", "is", "CS50"]
uppercased = map(str.upper, words)
print(*uppercased)
Keywords
break
: leave the loopcontinue
: skip to next iteration
Libraries
import lib
lib.component(...)
from lib import component
component(...)
Packages
A package is a collection of libraries in the same directory, often built by other developers.
You can download user packages on pypi.org.
Install Packages with Pip
pip
is a package manager for Python.
pip install package
Useful Libraries
random
Generate random numbersshuffle
choice
randint
statistics
mean
requests
Web requests (similar tocurl
) useful for interfacing with APIs
APIs
APIs usually communicate in JSON.
import requests, sys
import json
response = requests.get("<https://itunes.apple.com/search?entity=song(...)>")
print(response.json()) # Print respose formatted for json (as a py dictionary))
print(json.dumps(response.json(), indent=2)) # Print response indented to read easily.
o = response.json()
for result in o["results"]:
print(result["trackName"]) # Print all songs in the response
Create Custom Library
# LIBRARY: lib.py file
def main():
hello("world")
def hello(name):
print(f"hello, {name}")
# Only call main if ran from the command line. Not as a library.
if __name__ == "__main__":
main()
# MAIN CODE: main.py file
from lib import hello
hello("trude")
Functions
def hello(name):
print(f'Hello {name}')
hello("trude")
Default Values
def hello(to='world'):
print("hello,", to)
hello() # hello, world
hello('trude') # hello, trude
Main Function
def main():
# main code ...
# other fucntions ...
main()
Generator Function (Yield)
Return one value at a time, without ending the function, and then loop again.
Useful when working with a large amount of logic that takes a long time to execute.
def sheep(n):
for i in range(n):
yield "SHEEP" * i
yield
returns an iterator that allows the program to handle one element at a time and not lose track.
Command Line Arguments
from sys import argv
if len(argv) == 2:
print(f"Hello, {argv[1]}")
else:
print("Hello World.")
# argv[0] is the program name
# List all arguments
for arg in argv:
print(arg)
Flags
To support commands like: python file.py -n 2
import argparse
parser = argparse.ArgumentParser(description="Meow like a cat")
parser.add_argument("-n", default=1, type=int, help="number of times to meow")
args = parser.parse_args()
for _ in range(args.n): # .n is the -n flag
print("meow")
Allow Function to Take Any Number of Arguments (Unpack)
def f(*args, **kwargs):
print("Positional: ", args)
print("Named: ", kwargs)
f(100, 50, 25) # Positional: (100, 50, 25)
f(100, 50, 25, 5) # Positional: (100, 50, 25, 5)
f(gold=10, silver=20, copper=1) # Named: {'gold': 10, 'silver'20 ...}
Pass Functions as Arguments
def get_name(student):
return student["name"] # Sort by student name
for student in sorted(students, key=get_name):
...
Lambda Function
Pass a function without having to give it a name.
for student in sorted(students, key=lambda student: student["name"]):
...
Exceptions
# Int
try: # Try to execute
x = int(input("What's your number?"))
except ValueError: # If error is ValueError
print("Not a number.")
except: # If error
print("Unknown Error.")
else: # If success
print(f"Your number+1 is {x + 1}")
try:
...
except:
pass # Catch the error, but then ignore it.
Operators
Comparison Operators
<
>
≤
≥
≠
==
Logic Operators
and
or
s = input("Do you agree?")
if s == 'y' or s == 'Y' or s == "Yes" or s == "yes":
(...)
# This can be improved:
s = input("Do you agree?").lower()
if s in ['y', 'yes']:
(...)
Scope
- Program
- Function (Variables in loops and IFs are global to the function)
Exit with Error Codes
from sys import exit
exit(1) # Exit with error code 1
exit("Failed for some reason")
Unit Tests
Helper code to test the main code and (hopefully) catch bugs before they can reach production.
Manual Tests
Main code
def main():
x = int(input("X value: "))
print(f"X^2 is {square(x)}")
def square(n):
return(n * n)
if __name__ = "__main__":
main()
Test code (Using IF)
from file import square
def main():
test_square()
def test_square():
if square(2) != 4:
print("2 squared was not 4.")
if square(3) != 9:
print("3 squared was not 9.")
if __name__ == "__main__":
main()
Improved test code (Using assert)
from file import square
def main():
test_square()
def test_square():
try:
assert square(2) == 4
except AssertionError:
print("2 squared was not 4.")
try:
assert square(3) == 9
except AssertionError:
print("3 squared was not 9.")
if __name__ == "__main__":
main()
Pytest
pytest
is an external program that simplifies python’s unit testing.
import pytest
from file import square
def test_square():
assert square(2) == 4
assert square(3) == 9
assert square(-2) == 4
assert square(-3) == 9
assert square(0) == 0
def test_str(): # Verify that an error will happen for a str
with pytest.raises(TypeError):
square("cat")
Test with pytest
:
pytest test_file.py
A function with side effects (doesn’t return a value) can’t be tested.
File I/O
Write to a File (Replace)
name = "trude"
file = open("name.txt", "w")
file.write(name)
file.close()
Append to a File (Add)
name = "trude"
file = open("name.txt", "a")
file.write(name)
file.close()
Open a File and close Automatically
name = "trude"
with open("name.txt", "a") as file:
file.write(name) \\#File is only open in this scope
Read a File
"r"
is optional when reading.
with open("name.txt", "r") as file:
lines = file.readlines() # Return all lines as a list
for line in lines:
print(line.rstrip()) # Print all lines and remove \\n separating each line
Better Code for Reading Every line
with open("name.txt") as file:
for line in file:
print(line.rstrip())
Sort File Lines
names = []
with open("name.txt") as file:
for line in file:
names.append(line.rstrip())
for name in sorted(names):
print(f"Hello, {name}")
CSV Files
Read
Python
import csv
students = []
with open("students.csv") as file:
reader = csv.reader(file)
for name, home in reader:
students.append({"name": name, "home": home})
for student in students:
print(f"{student['name]"} is from {student['home']}")
CSV File
trude, myHome
maxs, hisHome
jcionx, anotherHome
Dict Reader
Ignores column order and doesn’t break the program if new columns are added. It is recommended to always use **DictReader**
instead of **Reader**
.
Python
import csv
students = []
with open("students.csv") as file:
reader = csv.DictReader(file)
for row in reader:
students.append({"name": row["name"], "home": row["home"]})
for student in students:
print(f"{student['name]"} is from {student['home']}")
CSV File
name, home
trude, myHome
maxs, hisHome
jcionx, anotherHome
Write
import csv
name = 'trude'
home = 'myHome'
with open("students.csv", "a") as file:
writer = csv.writer(file)
writer.writerow([name, home])
Dict Writer
import csv
name = 'trude'
home = 'myHome'
with open("students.csv", "a") as file:
writer = csv.DictWriter(file, fieldnames=["name", "home"])
writer.writerow({"name": name, "home": home})
Other Formats
- TXT
- CSV
- JSON
- BINARY
- Images (PIL library)
Animated GIF Program
from PIL import Image
items = ["image1.png", "image2.png"]
images = []
for item in items:
image = Image.open(item)
images.append(image)
images[0].save(
"images.gif", save_all=True, append_images=[images[1]], duration=200, loop=0
)
Regular Expressions (regex)
Define patterns for comparisons.
import re
email = input("Email Address: ").strip()
if re.search(r"^.+@.+\\.edu$", email, re.IGNORECASE):
print("Email is valid.")
else:
print("Email is not valid.")
Regular Expression Symbols
.
any character except a newline- 0 or more repetitions
+
1 or more repetitions?
0 or 1 repetition\\
escape character{m}
m repetitions{m,n}
m-n repetitions (range)^
match the start of the string$
match the end of the string[]
set of characters[^]
complementing the set\\d
decimal digit\\D
not a decimal digit\\s
whitespace characters\\S
not a whitespace character\\w
word character, numbers and underscore\\W
not a word characterA|B
either A or B(…)
a group(?:…)
non-capturing version
Always user"string"
(raw string) so python won’t interpret\\
as a special character.
RE Lib Flags
re.IGNORECASE
re.MULTILINE
re.DOTALL
Examples
Regular Expression for Email Validation
import re
regex = re.compile(r"^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$")
def isValid(email):
if re.fullmatch(regex, email):
print("Valid email")
else:
print("Invalid email")
More regular expressionscompile
caches the query to make new lookups faster.
When a regular expression becomes too complex, the rule of thumb is to use a library instead.
Object-Oriented Programming: OOP
Tuple
An immutable (constant) list.
tuple = (val1, val2)
Return More than One Value from a Function
def get_student():
n = input("Name: ")
h = input("House: ")
return n, h
name, house = get_student()
print(name)
student = get_student()
print(student[0])
To make the values mutable, return a list instead.
return [item1, item2]
Class
Classes are ‘blueprints’ for data; They define custom data types.
For example, you can use a class to represent a real-world entity.
Basic Class
class Student:
... # '...' is a valid placeholder
student = Student # Create an object from the Student class
student.name = "trude" # Add a new instance variable
student.house = "myHome"
print(student.name) # 'trude'
Attributes
class Student:
def __init__(self, name, house): # Initialization function
self.name = name
self.house = house
name = 'trude'
house = 'myHome'
student = Student(name, house)
self
is the object created from the class definition.- When an object is created, the
__init__
function is executed.
Attributes Error Handling
class Student:
def __init__(self, name="Unknown", house): # Initialization function
if not name:
raise ValueError("Missing name") # Create and output a custom error
if house not in ["myHome", "yourHome", "hisHome"]:
raise ValueError("Invalid house")
self.name = name
self.house = house
Change what Happens when an Object is Printed
class Student:
def __init__(self, name, house): # Initialization function
self.name = name
self.house = house
def __str__(self):
return f"A Student - {self.name}"
student = Student("trude", "myHome")
print(student) # "A Student - trude"
Methods
class Mage:
def __init__(self, name, clan, element): # Initialization function
self.name = name
self.clan = clan
self.element = element
def castElement(self):
match self.element:
case "Fire":
return "FIRE SPELL"
case "Water":
return "Water SPELL"
case "Earth":
return "Earth SPELL"
case "Air":
return "AIR SPELL"
case _:
return "NO SPELL"
mage = Mage("trude", "magicINC", "Fire")
print(mage.castElement())
Properties
Dot notation (student.name = ""
) can bypass any data validation. To avoid this, make attributes constant.
A constant attribute is referred to as a property.
class Mage:
def __init__(self, name, clan, element): # Initialization function
self.name = name
self.clan = clan
self.element = element
# Getter (function to get house attribute)
@property # Indicates that this is a getter
def clan(self):
return self._clan # Add _ to avoid name collision.
# Setter (function to set a value)
@clan.setter # Indicates that this is a setter
def clan(self, clan):
if clan not in ["magicINC", "spellInator", "glyphGens"]:
raise ValueError("Invalid Clan")
self._clan = clan
mage = Mage("trude", "spellInator", "Fire")
mage.clan = "not-a-clan"
Example
class Mage:
...
def main():
mage = get_mage()
print(f"{mage.name} from {mage.clan}")
def get_mage():
mage = Mage()
mage.name = "trude"
mage.clan = "spellInator"
return mage
if __name__ == "__main__":
main()
Class Methods
A method that relates to the class itself, and doesn’t depend on the objects individually.
import random
class Hat:
def __init__(self):
self.clans = ["magicINC", "spellInator", "glyphGen"]
def sort(self, name):
print(name "is in", random.choice(self.clans))
hat = Hat()
hat.sort("Trude")
Class Variables
self.var
A variable unique for each objectvar
A variable shared with all objects
class Hat:
clans = ["magicINC", "spellInator", "glyphGen"]
@classmethod
def sort(cls, name):
print(name "is in", random.choice(cls.clans))
Hat.sort("Trude")
A class method is a method global to the class, instead of created for each object. It relates to the data type (class) itself.
Example
class Mage:
...
@classmethod
def get(cls):
name = input("Name: ")
clan = input("Clan: ")
return cls(name, clan) # name and clans are returned to the class as self.name and self.clan.
...
def main():
mage = Mage.get()
print(mage)
if __name__ == "__main__":
main()
Inheritance
Inherit code from a parent class to avoid code duplication.
class Person:
def __init__(self, name)
if not name:
raise ValueError("Missing name")
self.name = name
class Student(Person): # Pass Person to Student
def __init__(self, name, house):
super().__init__(name) # Execute Person's __init__ method.
self.house = house
...
class Professor(Person):
def __init__(self, name, subject):
super().__init__(name)
self.subject = subject
...
person = Person("Random Guy")
student = Student("Trude", "myHome")
professor = Professor("Someone", "Math")
Operator Overloading
Customize what an operator does with a Class.
__add__
Behavior of ‘+’ operator.
class Vault:
def __init__(self, gold=0, silver=0, copper=0):
self.gold = gold
self.silver = silver
self.copper = copper
def __str__(self):
return f"{self.gold} Gold, {self.silver} Silver, {self.copper} Copper."
def __add__(self, other):
gold = self.gold + other.gold
silver = self.silver + other.silver
copper = self.copper + other.copper
return Vault(gold, silver, copper)
trude = Vault(100, 50, 25)
jcionx = Vault(25, 50, 100)
print(trude) # 100 Gold, 50 Silver, 25 Copper
print(jcionx) # 25b Gold, 50 Silver, 100 Copper
total = trude + jcionx
print(total) # 125b Gold, 100 Silver, 125 Copper