Chapter 1, Systems Design

Chapter 2, Objects in Python

Chapter 3, When Objects Are Alike

class Contact(object): 			# syntax: class(superclass)
	all_contacts: List["Contact"] = [] 	# class variable
	def __init__(self, name: str, email: str) -> None:
		self.name = name 	# self: each time a different name is appended to an object
		self.email = email 
		contact.all_contacts.append(self) # append any new contact
class Supplier(Contact): 			# inheritance, having also name & email available for use
	def order(self, order: "Order") -> None
		print(f"This would send an {order} to {self.name}") 	# name can be used
		class Friend(Contact):
	def __init__(self, name, email, phone: str): 	# overrides superclass Contact's init
		super.__init__(name, mail) 	# binds instance to parent class, inits itself
self.phone = phone 		# sets phone attrib
class Emailable(Protocol): email: str		 		# hint: Emailable
class MailSender(Emailable): def send_email(self, message) 	# this is the mixin
# "if MailSender is emailable (i.e. has an email: str) field, then send_email"

Chapter 4, Expecting the Unexpected

Chapter 5, When to Use Object-Oriented Programming

Chapter 6, Abstract Base Classes and Operator Overloading

Chapter 7, Python Data Structures

Chapter 8, The Intersection of Object-Oriented and Functional Programming

Chapter 9, Strings, Serialization, and File Paths

Chapter 10, The Iterator Pattern

Chapter 11, Common Design Patterns

Chapter 12, Advanced Design Patterns

Chapter 13, Testing Object-Oriented Programs

Chapter 14, Concurrency