Object-Oriented Programming (Intro)面向对象编程(入门)
Object-oriented programming (OOP) is a way of organising code around objects — bundles that combine data (attributes) and behaviour (methods) into a single unit. You define a class as the blueprint, then create as many instances as you need. A Dog class describes what every dog has and can do; each individual dog (Fido, Bella) is a separate object. This guide covers Python OOP from scratch: defining classes, writing instance variables, calling methods, building constructors with __init__, and a first look at encapsulation and inheritance. All code is Python; it feeds directly into AP CSA Java classes.面向对象编程(OOP,object-oriented programming)是一种将代码围绕对象(object)组织的方式——对象将数据(属性 attribute)和行为(方法 method)捆绑为一个单元。你把类(class)定义为蓝图,然后按需创建任意数量的实例(instance)。Dog 类描述每条狗拥有什么、能做什么;每条具体的狗(Fido、Bella)是独立的对象。本指南从零开始讲授 Python OOP:定义类、编写实例变量、调用方法、用 __init__ 构建构造函数(constructor),以及初步了解封装(encapsulation)与继承(inheritance)。全部代码为 Python,直接为 AP CSA Java 类打基础。
How to use this guide如何使用本指南
OOP is an advanced / optional topic across all four curricula at the high-school foundations level. If you are taking ICS4U (Ontario Grade 12), CSE3120 (Alberta Advanced), or Computer Programming 12 (BC), this guide is core material. If you are on the AP CSA track, this guide is the Python warm-up before the Java class-creation unit. If you are in ICS3U, AP CSP, or CSE1110, OOP is not assessed at your level — bookmark this for later. All code in this guide is Python. The seven sections build in order: you need §1 (what OOP is) before §2 (defining a class) before §5 (constructors).在所有四个课程体系的高中基础级别,OOP 都是进阶/可选主题。如果你正在学习 ICS4U(安大略 12 年级)、CSE3120(阿尔伯塔进阶)或 Computer Programming 12(BC),本指南是核心内容。如果你在 AP CSA 轨道,本指南是进入 Java 类创建单元之前的 Python 热身。如果你在 ICS3U、AP CSP 或 CSE1110,OOP 在你的级别不做考核——先收藏,待以后使用。本指南中所有代码均为 Python。七个章节按顺序递进:需先掌握 §1(OOP 是什么)再学 §2(定义类),再学 §5(构造函数)。
Memorise five things: class = blueprint, object = instance; __init__ is the constructor; self refers to the current object; attributes are per-instance variables; methods are functions inside the class. Read every cram-cheat box. The flashcards cover exam vocabulary cold.背熟五件事:类 = 蓝图,对象 = 实例;__init__ 是构造函数;self 指当前对象;属性是每个实例的变量;方法是类内部的函数。读每个速记框。闪卡涵盖考试词汇的冷知识。
Work through every worked example by typing the code yourself and running it. Predict the output before you run it. For §7 (encapsulation), understand why hiding data behind methods is a design benefit, not just what it is. The going-deeper box in §7 introduces inheritance — the topic AP CSA returns to in Units 8–9.亲手输入并运行每个例题代码。运行前预测输出。对于 §7(封装),理解为什么将数据隐藏在方法后面是设计上的优点,而不仅仅是它是什么。§7 的深入框介绍继承——AP CSA 在第 8-9 单元会重返这个主题。
What is OOP? Objects and Classes什么是面向对象编程?对象与类
- Class类(class) — the blueprint or template. Defines what data and behaviours all objects of this type share. A
Dogclass says "every dog has a name and an age and can bark." CSE3120 outcome 1.1.5: "use of classes and objects."— 蓝图或模板。定义该类型所有对象共有的数据和行为。Dog类说明"每条狗都有名字和年龄,都能叫。" CSE3120 结果 1.1.5:"类和对象的使用。" - Object / Instance对象 / 实例(object / instance) — a concrete realisation of the class blueprint.
fido = Dog("Fido", 3)creates one specific dog object. Each object has its own copy of the data.— 类蓝图的具体实现。fido = Dog("Fido", 3)创建一个具体的狗对象。每个对象都有自己的数据副本。 - Real-world modelling现实世界建模(real-world modelling) — OOP maps naturally to real things: a
BankAccounthas a balance and an owner and can deposit/withdraw. ICS4U C1.1: "decompose a problem into modules, classes, or abstract data types using an object-oriented design methodology."— OOP 自然地映射到现实事物:BankAccount有余额和所有者,能存款/取款。ICS4U C1.1:"使用面向对象设计方法将问题分解为模块、类或抽象数据类型。"
dog1_name, dog1_age, dog2_name, dog2_age …, you define a Dog class once and create as many dog objects as you need. Each object is self-contained.关键洞见:不必写分散的变量 dog1_name、dog1_age、dog2_name、dog2_age……,只需定义一次 Dog 类,然后按需创建任意数量的狗对象。每个对象都是自包含的。
Model two dogs (Fido age 3, Bella age 5). Show the difference between procedural (separate variables) and OOP (class instance) approaches.建模两条狗(Fido 3 岁,Bella 5 岁)。展示过程式(分散变量)与面向对象(类实例)方式的区别。
Procedural approach (messy, hard to scale).过程式方式(混乱,难以扩展)。
dog1_name = "Fido"
dog1_age = 3
dog2_name = "Bella"
dog2_age = 5
# Adding dog3 means adding two more variables...
Procedural: each dog needs multiple separate variables; the code grows out of control as the number of dogs increases.过程式:每条狗需要多个独立变量,数量增加时代码迅速失控。
OOP approach (clean, scalable).面向对象方式(简洁,可扩展)。
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
fido = Dog("Fido", 3)
bella = Dog("Bella", 5)
print(fido.name, fido.age) # Fido 3
print(bella.name, bella.age) # Bella 5
OOP: the Dog class is defined once; fido and bella are independent instances, each holding their own name and age.面向对象:Dog 类定义一次;fido 和 bella 是各自独立的实例(instance,实例),各自持有自己的 name 和 age。
The Dog class is defined once. fido and bella are separate instances, each with their own data. Adding a third dog is one line: rex = Dog("Rex", 2).只需一行就能添加第三条狗:rex = Dog("Rex", 2)。
Car class and then write my_car = Car("Toyota", 2022). What is my_car?你定义了一个 Car 类,然后写了 my_car = Car("Toyota", 2022)。my_car 是什么?my_car is an instance of the Car class — a concrete object created from the blueprint. It has its own copy of the data ("Toyota", 2022).my_car 是 Car 类的一个实例——从蓝图创建的具体对象。它拥有自己的数据副本("Toyota",2022)。Car(...) creates an instance (object), not the class itself. The class is defined with the class keyword above.调用 Car(...) 创建一个实例(对象),而不是类本身。类是用上方的 class 关键字定义的。Going deeper — OOP vs procedural paradigms (CSE3120 1.1 / ICS4U C1)深入 — 面向对象与过程式范式对比(CSE3120 1.1 / ICS4U C1)
CSE3120 outcome 1.1.1 describes OOP as "implementation by the exchange of 'messages' among 'objects'." In practice this means calling methods on objects: fido.bark() sends a "bark" message to the fido object. ICS4C A3.4 (verbatim): "compare and contrast object-oriented and procedural programming paradigms." Procedural code is a sequence of function calls acting on separate data; OOP bundles data and the functions that operate on it together. The bundling is called encapsulation — covered in §7.CSE3120 结果 1.1.1 将 OOP 描述为"通过'对象'间'消息'交换实现"。实际上这意味着在对象上调用方法:fido.bark() 向 fido 对象发送"bark"消息。ICS4C A3.4(原文):"比较和对比面向对象与过程式编程范式。"过程式代码是一系列作用于独立数据的函数调用;OOP 将数据和操作数据的函数捆绑在一起。这种捆绑称为封装——在 §7 中介绍。
Defining a Class定义类
class ClassName:
def __init__(self, param1, param2):
self.attr1 = param1
self.attr2 = param2
def method_name(self):
# body
pass
class ClassName:— declares the class. Convention: CapWords (PascalCase). E.g.BankAccount,StudentRecord.— 声明类。惯例:大写驼峰(PascalCase)。如BankAccount、StudentRecord。def __init__(self, ...):— the constructor; called automatically when you create a new object. Sets up the object's initial data. Covered in depth in §5.— 构造函数(constructor,构造函数);创建新对象时自动调用,设置对象的初始数据。在 §5 中深入介绍。self— the first parameter of every method; it refers to the current object. Python passes it automatically — you do not pass it when calling the method.— 每个方法的第一个参数;指代当前对象。Python 自动传递self——调用方法时无需手动传入。
Define a Student class with a name and a grade (0–100). Add a method is_passing() that returns True if grade ≥ 50.定义一个 Student 类,包含姓名和成绩(0–100)。添加方法 is_passing(),如果成绩 ≥ 50 则返回 True。
class Student:
def __init__(self, name, grade):
self.name = name
self.grade = grade
def is_passing(self):
return self.grade >= 50
# Create two instances
s1 = Student("Alice", 78)
s2 = Student("Bob", 42)
print(s1.name, s1.is_passing()) # Alice True
print(s2.name, s2.is_passing()) # Bob False
Code notes: class Student: defines the class; def __init__(self, name, grade): is the constructor; self.name and self.grade are instance attributes; def is_passing(self): is an instance method; s1 = Student("Alice", 78) creates an instance.代码注解:class Student: 定义类;def __init__(self, name, grade): 构造函数,self.name 和 self.grade 是实例属性(instance variable,实例变量);def is_passing(self): 是实例方法;s1 = Student("Alice", 78) 创建实例。
Key points: (1) self.name and self.grade are stored per-object — s1 and s2 each have their own copies. (2) is_passing() uses self.grade to access the current object's data. (3) You call the method as s1.is_passing(), not Student.is_passing(s1) (Python does that internally).要点:(1) self.name 和 self.grade 按对象存储——s1 和 s2 各有自己的副本。(2) is_passing() 用 self.grade 访问当前对象的数据。(3) 调用方式为 s1.is_passing(),而非 Student.is_passing(s1)(Python 在内部完成这一步)。
Student example, what does self refer to inside is_passing()?在 Student 例子中,is_passing() 内部的 self 指代什么?self refers to the specific object that the method was called on. When you write s1.is_passing(), self inside the method is s1. When you write s2.is_passing(), self is s2.self 指代调用该方法的具体对象。写 s1.is_passing() 时,方法内部的 self 就是 s1;写 s2.is_passing() 时,self 就是 s2。self is not the class itself — it is the instance. It lets the method access the current object's own data via self.attribute.self 不是类本身,而是实例。它让方法通过 self.属性 访问当前对象自己的数据。Attributes (Instance Variables)属性(实例变量)
- Defined with
self.attr = value用self.attr = value定义 — always inside__init__. Every object of the class then has its own copy of that attribute. ICS4C B2.1: "create and use instance methods (e.g., constructors, mutators, accessors)."— 总是在__init__内部定义。该类的每个对象都有自己的属性副本。ICS4C B2.1:"创建和使用实例方法(如构造函数、修改器、访问器)。" - Per-instance (not shared)每个实例独立(不共享) — changing
s1.gradedoes not affects2.grade. Each object's attributes are independent. This is the core benefit of OOP over global variables.— 修改s1.grade不影响s2.grade。每个对象的属性是独立的。这是 OOP 相较于全局变量的核心优势。 - Access with dot notation:
object.attribute用点号访问:对象.属性—s1.namereads Alice's name;s1.name = "Alicia"updates it. CSE3120 1.1.3: "use of private, public and protected members, accessors and modifiers to control access to data."—s1.name读取 Alice 的姓名;s1.name = "Alicia"更新它。CSE3120 1.1.3:"使用私有、公有和受保护成员、访问器和修改器来控制数据访问。"
Define a BankAccount class with owner and balance attributes. Create two accounts and show that their balances are independent.定义一个 BankAccount 类,包含 owner(所有者)和 balance(余额)属性。创建两个账户并证明它们的余额是独立的。
class BankAccount:
def __init__(self, owner, balance):
self.owner = owner
self.balance = balance
acc1 = BankAccount("Alice", 1000)
acc2 = BankAccount("Bob", 500)
acc1.balance += 200 # deposit $200 into Alice's account
print(acc1.owner, acc1.balance) # Alice 1200
print(acc2.owner, acc2.balance) # Bob 500 (unchanged)
Code notes: self.owner and self.balance are instance variables. acc1 and acc2 are independent objects. Changing acc1.balance does not affect acc2.balance.代码注解:self.owner 和 self.balance 是实例变量(instance variable,实例变量),acc1 与 acc2 各自独立。修改 acc1.balance 不影响 acc2.balance。
Notice: acc1.balance += 200 modifies only Alice's account object. Bob's account is completely separate in memory. This isolation is impossible with procedural global variables.注意:acc1.balance += 200 只修改 Alice 的账户对象。Bob 的账户在内存中完全独立。这种隔离是过程式全局变量无法实现的。
a = Dog("Rex", 4) and b = Dog("Pip", 2), you run a.age = 5. What is b.age?执行 a = Dog("Rex", 4) 和 b = Dog("Pip", 2) 后,运行 a.age = 5。b.age 是多少?a.age has no effect on b.age. b was created with age 2, and that value is unchanged. b.age is still 2.实例属性是每个对象独立的。修改 a.age 对 b.age 没有影响。b 创建时 age 为 2,该值未改变。b.age 仍然是 2。__init__ using self.attribute = value. This ensures every new object gets its own copy of each attribute when it is created.实例属性在 __init__ 内使用 self.属性 = 值 定义。这确保每个新对象在创建时都能获得每个属性的自己副本。self. inside a method are local variables, not instance attributes. Instance attributes require self. and are typically set in __init__.在方法内部不加 self. 定义的变量是局部变量,而非实例属性。实例属性需要 self.,通常在 __init__ 中设置。Methods方法
- Always have
selfas first parameter第一个参数始终为self—def describe(self):. You call it asobj.describe()— Python passesselfautomatically.—def describe(self):。调用时写obj.describe()——Python 自动传入self。 - Methods can take extra parameters方法可以有额外参数 —
def deposit(self, amount):takes one extra argument. Call:acc.deposit(100). ICS4C B2.1: "create and use instance methods."—def deposit(self, amount):额外接收一个参数。调用:acc.deposit(100)。ICS4C B2.1:"创建和使用实例方法。" - Methods can return values方法可以返回值 —
def get_balance(self): return self.balance. This is the accessor (getter) pattern. Methods that change state without returning are mutators (setters).—def get_balance(self): return self.balance。这是访问器(getter)模式。改变状态但不返回值的方法是修改器(setter)。
Extend the BankAccount class with deposit(amount) and withdraw(amount) methods, and a get_balance() accessor.扩展 BankAccount 类,添加 deposit(amount)(存款)和 withdraw(amount)(取款)方法,以及 get_balance() 访问器。
class BankAccount:
def __init__(self, owner, balance):
self.owner = owner
self.balance = balance
def deposit(self, amount): # mutator — changes state
self.balance += amount
def withdraw(self, amount): # mutator — changes state
if amount <= self.balance:
self.balance -= amount
else:
print("Insufficient funds")
def get_balance(self): # accessor — returns data
return self.balance
acc = BankAccount("Alice", 1000)
acc.deposit(200)
acc.withdraw(50)
print(acc.get_balance()) # 1150
Code notes: deposit and withdraw are mutator methods that change self.balance; get_balance is an accessor method that only reads and returns data. When calling acc.deposit(200), Python automatically passes acc as self and 200 as amount.代码注解:deposit 和 withdraw 是修改器方法(mutator,修改器),改变 self.balance;get_balance 是访问器方法(accessor,访问器),只读取并返回数据。acc.deposit(200) 调用时 Python 自动将 acc 传给 self,200 传给 amount。
The withdraw method has a guard: if amount exceeds balance, it prints a message instead of creating a negative balance. This is encapsulation in action — the object protects its own data integrity.withdraw 方法有一个保护检查:如果取款额超过余额,则打印消息而不产生负余额。这是封装(encapsulation,封装)的实际体现——对象保护自身数据的完整性。
deposit method on a BankAccount object named acc to add $300?如何对名为 acc 的 BankAccount 对象调用 deposit 方法以存入 300 元?acc.deposit(300) is the correct dot-notation call. Python automatically passes acc as the self argument; you only supply the extra arguments (300 for amount).acc.deposit(300) 是正确的点号调用。Python 自动将 acc 作为 self 参数传入;你只需提供额外参数(amount 的 300)。object.method(args). Python inserts self automatically — never pass it explicitly in the call.方法调用使用点号表示法:对象.方法(参数)。Python 自动插入 self——调用时永远不要手动传入它。__init__, sets up the object when created.修改器 = 改变状态。访问器 = 读取状态而不改变它。构造函数 = __init__,在创建时设置对象。Going deeper — method chaining and fluent APIs深入 — 方法链与流式 API
When a mutator returns self, you can chain calls: acc.deposit(100).deposit(50). This is the "fluent interface" pattern used in many Python libraries (e.g. Pandas df.dropna().reset_index()). For ICS4U / CSE3120-level work, understanding that methods can return self is part of the OOP design vocabulary. At the floor level, returning None from mutators (the default when no return statement is present) is perfectly correct and more common.当修改器返回 self 时,可以链式调用:acc.deposit(100).deposit(50)。这是许多 Python 库使用的"流式接口"模式(如 Pandas 的 df.dropna().reset_index())。对于 ICS4U / CSE3120 级别的学习,理解方法可以返回 self 是 OOP 设计词汇的一部分。在基础级别,修改器返回 None(没有 return 语句时的默认值)是完全正确的,也更常见。
Constructors (__init__)构造函数(__init__)
__init__ runs automatically every time you create a new object — four key points.__init__ 在每次创建新对象时自动运行 — 四个要点。
- Name is always
__init__名称始终为__init__— the double underscores (called "dunder") tell Python this is a special method. Never rename it.— 双下划线(称为"dunder")告知 Python 这是特殊方法。永远不要重命名它。 - Called by
ClassName(args)由类名(参数)调用 —Dog("Fido", 3)calls__init__(self, "Fido", 3)automatically. You never call__init__directly.—Dog("Fido", 3)自动调用__init__(self, "Fido", 3)。永远不要直接调用__init__。 - Sets up initial state设置初始状态 — its job is to assign starting values to all instance attributes. After
__init__finishes, the object is ready to use.— 其任务是为所有实例属性赋初始值。__init__完成后,对象即可使用。 - Can set defaults可以设置默认值 —
def __init__(self, name, balance=0):makesbalanceoptional.BankAccount("Alice")creates an account with balance 0.—def __init__(self, name, balance=0):使balance可选。BankAccount("Alice")创建余额为 0 的账户。
Create a Rectangle class. The constructor takes width and height. Add an area() method and a is_square() method.创建一个 Rectangle(矩形)类。构造函数接受 width(宽)和 height(高)。添加 area()(面积)方法和 is_square()(是否为正方形)方法。
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def is_square(self):
return self.width == self.height
r1 = Rectangle(5, 3)
r2 = Rectangle(4, 4)
print(r1.area()) # 15
print(r1.is_square()) # False
print(r2.area()) # 16
print(r2.is_square()) # True
Code notes: Rectangle(5, 3) triggers __init__(self, 5, 3), setting self.width=5 and self.height=3; r1.area() returns 5 * 3 = 15; r2.is_square() checks 4 == 4, which is True.代码注解:Rectangle(5, 3) 触发 __init__(self, 5, 3),设置 self.width=5、self.height=3;r1.area() 返回 5 * 3 = 15;r2.is_square() 检查 4 == 4 为 True。
Trace through r1 = Rectangle(5, 3): Python calls Rectangle.__init__(r1, 5, 3). Inside: self.width = 5 and self.height = 3. After __init__ returns, r1 is a fully initialised object with both attributes set.追踪 r1 = Rectangle(5, 3):Python 调用 Rectangle.__init__(r1, 5, 3)。内部:self.width = 5 且 self.height = 3。__init__ 返回后,r1 是已完全初始化的对象,两个属性均已设置。
__init__?Python 何时调用 __init__?__init__ is called automatically every time a new instance is created. Dog("Fido", 3) triggers __init__ to set up the new object's attributes. You never call it directly.__init__ 在每次创建新实例时自动调用。Dog("Fido", 3) 触发 __init__ 设置新对象的属性。你永远不要直接调用它。__init__ is the constructor — it runs once at object creation. It does not run when you call other methods or delete the object (__del__ handles deletion).__init__ 是构造函数——在对象创建时运行一次。调用其他方法或删除对象时不会运行(__del__ 处理删除)。class Circle: def __init__(self, radius): self.radius = radius, what does c = Circle(7) do?已知 class Circle: def __init__(self, radius): self.radius = radius,c = Circle(7) 做什么?Circle(7) creates a new instance. Python calls __init__(self, 7), which runs self.radius = 7. The result is stored in c, so c is a Circle object with c.radius == 7.Circle(7) 创建一个新实例。Python 调用 __init__(self, 7),执行 self.radius = 7。结果存入 c,所以 c 是一个 c.radius == 7 的 Circle 对象。Circle(7) creates a new instance of it, not a new class definition.类已在上方定义。Circle(7) 创建该类的一个新实例,而不是新的类定义。Creating and Using Objects创建与使用对象
- Create (instantiate)创建(实例化) —
obj = ClassName(args). Calls__init__automatically. AB CSE3120 2.3.3: "domain analysis" of what objects are needed. ICS4C B2.2: "design a simple base class … using program templates."—obj = 类名(参数)。自动调用__init__。AB CSE3120 2.3.3:"分析域对象"确定需要哪些对象。ICS4C B2.2:"使用程序模板设计简单基类"。 - Use (call methods, read/write attributes)使用(调用方法、读/写属性) —
obj.method()orobj.attribute. Store multiple objects in a list to process them together:students = [s1, s2, s3].—obj.方法()或obj.属性。将多个对象存入列表一起处理:students = [s1, s2, s3]。 - Pass objects to functions将对象传递给函数 — objects are first-class values. You can pass a
Studentto a function, return one from a function, or store a list of them. CSE3120 3.3: "create the classes necessary to instantiate the objects called for by the algorithm."— 对象是一等值。你可以将Student传给函数、从函数返回,或存储它们的列表。CSE3120 3.3:"创建算法所需的类以实例化对象。"
Create five Student objects, store them in a list, and find the class average and the top scorer.创建五个 Student 对象,存入列表,计算班级平均分和最高分学生。
class Student:
def __init__(self, name, grade):
self.name = name
self.grade = grade
def is_passing(self):
return self.grade >= 50
# Create objects and store in a list
roster = [
Student("Alice", 88),
Student("Bob", 72),
Student("Carol", 95),
Student("David", 61),
Student("Emma", 45),
]
# Compute class average
total = sum(s.grade for s in roster)
avg = total / len(roster)
print(f"Class average: {avg:.1f}") # 72.2
# Find top scorer
top = max(roster, key=lambda s: s.grade)
print(f"Top scorer: {top.name} ({top.grade})") # Carol (95)
# List failing students
failing = [s.name for s in roster if not s.is_passing()]
print("Failing:", failing) # ['Emma']
Code notes: sum(s.grade for s in roster) iterates over the object list and accesses each object's grade attribute; max(..., key=lambda s: s.grade) finds the maximum by comparing attributes; s.is_passing() calls an instance method inside a list comprehension.代码注解:sum(s.grade for s in roster) 遍历对象列表并访问每个对象的 grade 属性;max(..., key=lambda s: s.grade) 通过比较属性找最大值;s.is_passing() 在列表推导中调用实例方法。
Key pattern: iterate over a list of objects with a for loop and call methods or read attributes on each one. This is OOP's main productivity advantage over procedural code for managing collections of related data.关键模式:用 for 循环遍历对象列表,对每个对象调用方法或读取属性。对于管理相关数据集合,这是 OOP 相较过程式代码的主要生产力优势。
dogs = [Dog("Fido",3), Dog("Bella",5)]. How do you print the name of the first dog?有列表 dogs = [Dog("Fido",3), Dog("Bella",5)]。如何打印第一条狗的名字?dogs[0] retrieves the first object in the list (Fido). Then .name accesses its name attribute. Result: "Fido".dogs[0] 取列表中第一个对象(Fido)。然后 .name 访问其名字属性。结果:"Fido"。dogs is a list, not an object — it has no .name. You first index into the list to get an object, then use dot notation: dogs[0].name.dogs 是列表,不是对象——它没有 .name。先用索引从列表取对象,再用点号:dogs[0].name。max(roster, key=lambda s: s.grade) return?max(roster, key=lambda s: s.grade) 返回什么?max(iterable, key=...) returns the element with the maximum key value — here, the Student object whose .grade is largest. To get just the number, you would write max(s.grade for s in roster).max(可迭代对象, key=...) 返回键值最大的元素——这里是 .grade 最大的 Student 对象。若只想要数值,写 max(s.grade for s in roster)。max(..., key=...) returns the whole object, not the key value. To get the grade number from the result, use .grade on the returned object.max(..., key=...) 返回整个对象,而非键值本身。要从结果获取成绩数值,对返回对象用 .grade。Encapsulation and a Peek at Inheritance封装与继承初探
- What it is是什么 — keeping an object's data private and exposing it only through methods. ICS4U C1.2: "demonstrate the ability to apply data encapsulation in program design (e.g., classes, records, structures)." CSE3120 1.1.2: "encapsulation" as a key feature of OOP.— 将对象数据保持私有,仅通过方法暴露。ICS4U C1.2:"展示在程序设计中应用数据封装的能力(如类、记录、结构体)。" CSE3120 1.1.2:"封装"为 OOP 关键特性。
- Why it matters为何重要 — the
withdrawmethod in §4 refused negative balances. Without encapsulation, code outside the class could setacc.balance = -999directly. Hiding data behind methods prevents invalid states.— §4 中的withdraw方法拒绝负余额。没有封装,类外代码可以直接设置acc.balance = -999。通过方法隐藏数据可防止无效状态。 - Python convention: prefix with underscorePython 惯例:用下划线前缀 —
self._balancesignals "treat as private, use the getter/setter." Python does not enforce access control the way Java does, but the convention is universal.—self._balance表示"视为私有,使用 getter/setter"。Python 不像 Java 那样强制访问控制,但这一惯例普遍通用。
Show encapsulation with a private _balance, then extend BankAccount to create a SavingsAccount subclass with an interest method.用私有 _balance 展示封装,再扩展 BankAccount 创建带利息方法的 SavingsAccount(储蓄账户)子类。
Encapsulation with private attribute.用私有属性实现封装。
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self._balance = balance # private by convention
def deposit(self, amount):
if amount > 0:
self._balance += amount
def withdraw(self, amount):
if 0 < amount <= self._balance:
self._balance -= amount
def get_balance(self): # accessor — safe read
return self._balance
Code notes: self._balance prefixed with underscore signals "private." External code should read via get_balance() and modify via deposit()/withdraw(), not by directly accessing acc._balance.代码注解:self._balance 加下划线表示"私有"(private,私有)。外部代码应使用 get_balance() 读取,使用 deposit()/withdraw() 修改,而不是直接访问 acc._balance。
Inheritance — SavingsAccount extends BankAccount.继承——SavingsAccount 继承 BankAccount。
class SavingsAccount(BankAccount): # inherits BankAccount
def __init__(self, owner, balance, rate):
super().__init__(owner, balance) # call parent __init__
self.rate = rate # new attribute
def add_interest(self): # new method
self._balance *= (1 + self.rate)
savings = SavingsAccount("Alice", 1000, 0.05)
savings.deposit(200) # inherited from BankAccount
savings.add_interest() # new method
print(savings.get_balance()) # 1260.0
Code notes: class SavingsAccount(BankAccount): declares inheritance; SavingsAccount is the subclass; BankAccount is the superclass. super().__init__(...) calls the parent constructor. savings.deposit(200) uses the deposit method inherited from the parent — no need to rewrite it.代码注解:class SavingsAccount(BankAccount): 声明继承(inheritance,继承),SavingsAccount 是子类(subclass,子类),BankAccount 是父类(superclass,父类)。super().__init__(...) 调用父类构造函数。savings.deposit(200) 使用的是从父类继承来的 deposit 方法,无需重写。
Inheritance says "a SavingsAccount is a BankAccount with extra features." It inherits all methods from the parent and adds new ones. CSE3120 1.1.2 lists "inheritance" as a key OOP feature. ICS4U A2.2 names "inheritance, method overloading, method overriding, polymorphism" as the full picture (covered in AP CSA). This guide stops at one level of inheritance.继承表示"SavingsAccount 是具有额外功能的 BankAccount"。它从父类继承所有方法并添加新方法。CSE3120 1.1.2 将"继承"列为关键 OOP 特性。ICS4U A2.2 命名了"继承、方法重载、方法覆盖、多态"(在 AP CSA 中完整介绍)。本指南止于一层继承。
_balance private and only allowing changes through deposit()/withdraw(), the class prevents invalid states (like negative balance). ICS4U C1.2 states this explicitly.封装将数据和方法捆绑在一起,并控制数据的修改方式。通过将 _balance 设为私有,只允许通过 deposit()/withdraw() 更改,类可防止无效状态(如负余额)。ICS4U C1.2 明确说明了这一点。class SavingsAccount(BankAccount):, what does BankAccount in parentheses mean?在 class SavingsAccount(BankAccount): 中,括号里的 BankAccount 意味着什么?class Child(Parent): declares inheritance. SavingsAccount inherits all methods and attributes from BankAccount and can add new ones or override existing ones.在 Python 中,class 子类(父类): 声明继承。SavingsAccount 继承 BankAccount 的所有方法和属性,并可添加新的或覆盖现有的。Going deeper — method overriding and polymorphism Honors — ICS4U A2.2 / CSE3130深入 — 方法覆盖与多态 荣誉 — ICS4U A2.2 / CSE3130
ICS4U A2.2 (verbatim) lists "encapsulation, inheritance, method overloading, method overriding, polymorphism" as modular design concepts. Method overriding: a subclass replaces a parent method with its own version. Example: SavingsAccount could override withdraw to refuse if the balance would fall below a minimum. Polymorphism: code that works on the parent type also works on any subclass — a function that takes a BankAccount parameter also accepts a SavingsAccount without changes. CSE3130 (Object-oriented Programming 2) extends this with UML design. These topics are the heart of AP CSA Units 8–10 (inheritance hierarchy, polymorphism, abstract classes).ICS4U A2.2(原文)列出"封装、继承、方法重载、方法覆盖、多态"为模块化设计概念。方法覆盖:子类用自己的版本替换父类方法。示例:SavingsAccount 可以覆盖 withdraw,在余额低于最低额时拒绝取款。多态:适用于父类类型的代码也适用于任何子类——接受 BankAccount 参数的函数无需修改也能接受 SavingsAccount。CSE3130(面向对象编程 2)通过 UML 设计扩展了这些内容。这些主题是 AP CSA 第 8-10 单元的核心(继承层次、多态、抽象类)。
Exam Strategy and Common Pitfalls考试策略与常见陷阱
- Use the correct terms.使用正确术语。 Examiners award marks for: class, instance/object, attribute/instance variable, method, constructor, encapsulation, inheritance, subclass. Saying "thing" or "box" loses marks. CSE3120 outcome 1.1 requires you to "describe the core concepts" by name.考官对以下词汇给分:类(class)、实例/对象(instance/object)、属性/实例变量(attribute/instance variable)、方法(method)、构造函数(constructor)、封装(encapsulation)、继承(inheritance)、子类(subclass)。说"东西"或"盒子"会失分。CSE3120 结果 1.1 要求你能按名称"描述核心概念"。
- Class vs instance distinction.类与实例的区别。 The single most common exam error: confusing the class (the blueprint) with an instance (the object). "The
Dogclass defines what a dog is;fidois an instance of it." Practice this sentence until it is automatic.最常见的考试错误:混淆类(蓝图)和实例(对象)。"Dog类定义狗是什么;fido是它的一个实例。"练习这句话直到自动说出。
- Trace object state by hand.手工追踪对象状态。 For "what is
obj.attrafter these lines?", draw a small table: one column per attribute, one row per line that modifies it. ICS4U and CSE3120 both assess "trace/read code to determine output."对于"这几行后obj.attr是什么?",画一个小表格:每个属性一列,每行修改它时填一行。ICS4U 和 CSE3120 都考核"追踪/阅读代码确定输出"。 - Remember
self.记住self。 In Python, every instance method must haveselfas its first parameter, and every attribute access inside a method must useself.attribute. Forgetting either is a guaranteed error.在 Python 中,每个实例方法必须以self为第一个参数,方法内每次属性访问必须用self.属性。忘记任一项都会导致错误。
- Explain encapsulation with a concrete example.用具体例子解释封装。 Do not just define it. Say: "The
_balanceattribute is private. Thewithdrawmethod checks that the amount is valid before subtracting, so external code cannot set a negative balance directly." Two sentences, one concrete example.不要只是定义。要说:"_balance属性是私有的。withdraw方法在减款前检查金额是否有效,因此外部代码无法直接设置负余额。"两句话,一个具体例子。 - Inheritance: is-a relationship.继承:is-a 关系。 A
SavingsAccountIS-ABankAccount— use inheritance. ACarHAS-AEngine— use composition (attribute), not inheritance. This distinction is ICS4U/CSE3130 territory.SavingsAccount是(IS-A)BankAccount——用继承。Car有(HAS-A)Engine——用组合(属性),而非继承。这一区别属于 ICS4U/CSE3130 范畴。
- Predict output before running.运行前预测输出。 On exam code questions, write out your predicted output, then check by tracing. If you can predict correctly, you understand the code; if not, trace line-by-line.在考试代码题中,先写出预测输出,再通过追踪检查。能正确预测说明你理解代码;若不能,逐行追踪。
- Python indentation is structural.Python 缩进是结构性的。 In Python, the body of a method must be indented under
def. Attribute assignments inside__init__must be indented twice (once for the class, once for the method). Off-by-one indentation errors are the most common Python OOP syntax mistake.在 Python 中,方法体必须在def下缩进。__init__内的属性赋值必须缩进两层(一层属于类,一层属于方法)。缩进错误是最常见的 Python OOP 语法错误。
Flashcards闪卡
class keyword.蓝图/模板,定义该类型每个对象将拥有的属性和方法。用 class 关键字定义。ClassName(args). Each instance has its own copy of the attributes.类的具体实现。用 类名(参数) 创建。每个实例拥有自己的属性副本。self.name = value inside __init__. Accessed with object.name.每个对象存储的数据。在 __init__ 内用 self.名称 = 值 定义。用 对象.名称 访问。self as first parameter. Called with obj.method(args).属于类的函数。始终以 self 为第一个参数。用 对象.方法(参数) 调用。__init__构造函数 — __init__(constructor)self refer to?self 指代什么?(What does self refer to?)self._balance. Signals "treat as private." Python does not enforce this — it is a convention.加单下划线前缀:self._balance。表示"视为私有"。Python 不强制——这是惯例。class Child(Parent):. Inherits all parent methods/attributes. Adds new ones or overrides existing ones. CSE3120 1.1.2; ICS4U A2.2.子类扩展父类:class 子类(父类):。继承父类所有方法/属性,可添加新的或覆盖现有的。CSE3120 1.1.2;ICS4U A2.2。super().__init__(...)super().__init__(...)__init__. Ensures the parent's attributes are set up before the child adds its own.在子类 __init__ 内调用父类构造函数。确保父类属性在子类添加自己属性之前已设置。BankAccount, StudentRecord. Functions/variables use snake_case.Python PEP 8 惯例:类名用 CapWords/PascalCase。如 BankAccount、StudentRecord。函数/变量用 snake_case。self.engine = Engine()).是(is-a)→ 用继承。储蓄账户是(is-a)银行账户。有(has-a)→ 用组合(属性)。汽车有(has-a)发动机(存为 self.engine = Engine())。Practice Quiz综合测验
Animal?定义名为 Animal 的类,正确的 Python 语法是什么?class Animal: uses the class keyword followed by the class name in PascalCase. The colon ends the header; the body is indented.class Animal: 使用 class 关键字,后跟 PascalCase 类名。冒号结束头部;主体缩进。def defines functions, not classes. Class syntax: class ClassName: — keyword, name, colon.def 定义函数,不是类。类语法:class 类名:——关键字、名称、冒号。class Dog:def __init__(self, name, age):self.name = nameself.age = ageWhat does
d = Dog("Rex", 5) produce?已知以上 Dog 类,d = Dog("Rex", 5) 产生什么?Dog("Rex", 5) creates a new Dog instance. Python calls __init__(self, "Rex", 5), setting self.name = "Rex" and self.age = 5. The object is stored in d.Dog("Rex", 5) 创建新 Dog 实例。Python 调用 __init__(self, "Rex", 5),设置 self.name = "Rex" 和 self.age = 5。对象存入 d。self automatically. The result is a Dog object with both attributes set, not a string or an error.Python 自动传入 self。结果是一个已设置两个属性的 Dog 对象,不是字符串或错误。bark(self) method that prints "Woof!". How do you call it on the dog d?你添加了一个打印 "Woof!" 的 bark(self) 方法。如何在狗 d 上调用它?d.bark() — dot notation, object first, method name, parentheses. Python passes d as self automatically. You never pass self explicitly in the call.d.bark()——点号,对象在前,方法名,括号。Python 自动将 d 作为 self 传入。调用时永远不要显式传入 self。object.method(). bark(d) would look for a standalone function named bark.方法调用用点号:对象.方法()。bark(d) 会查找名为 bark 的独立函数。_balance private and requiring callers to use deposit()/withdraw() prevents invalid values from being set. ICS4U C1.2.封装 = 私有数据 + 通过方法控制访问。将 _balance 设为私有并要求调用者使用 deposit()/withdraw(),可防止设置无效值。ICS4U C1.2。acc.balance = -500 directly bypasses validation — that is the opposite of encapsulation. Encapsulation requires controlling access through methods.直接设置 acc.balance = -500 绕过了验证——这是封装的对立面。封装要求通过方法控制访问。Readiness Checklist准备就绪清单
Tick each item when you can do it cold, without notes, on a first attempt.能在无笔记、首次尝试下完成,再勾选每一项。
- Explain the difference between a class and an object (instance) using a concrete real-world example. State verbatim CSTA 3B-AP-14 and explain why OOP is optional at that level. 🇺🇸 CSTA 3B-AP-14用具体现实例子解释类和对象(实例)的区别。逐字陈述 CSTA 3B-AP-14 并解释为何 OOP 在该级别是可选的。🇺🇸 CSTA 3B-AP-14
- Write a complete Python class from scratch (class keyword,
__init__with at least 2 attributes, and 2 methods — one mutator, one accessor). Use correct PascalCase for the class name. 🇨🇦 AB CSE3120 1.1.5 / ON ICS4C B2.1从零写出一个完整 Python 类(class 关键字、至少 2 个属性的__init__、2 个方法——一个修改器、一个访问器)。类名使用正确 PascalCase。🇨🇦 AB CSE3120 1.1.5 / ON ICS4C B2.1 - Explain what
selfmeans in a Python method and why it is needed. Demonstrate by tracing whatselfrefers to when you call a method on two different objects of the same class. 🇨🇦 ON ICS4U A2 / AB CSE3120解释 Python 方法中self的含义及其必要性。通过追踪在同一类的两个不同对象上调用方法时self分别指代什么来演示。🇨🇦 ON ICS4U A2 / AB CSE3120 - Describe encapsulation and explain how it prevents invalid object state. Give the Python private-attribute convention (
self._attr) and explain whywithdraw()is better than direct access to_balance. 🇨🇦 ON ICS4U C1.2 / AB CSE3120 1.1.2描述封装并解释它如何防止无效对象状态。给出 Python 私有属性惯例(self._attr)并解释为何withdraw()优于直接访问_balance。🇨🇦 ON ICS4U C1.2 / AB CSE3120 1.1.2 - Trace the output of a given Python class code snippet by hand (predict what each
printstatement will output, given a sequence of method calls). 🇨🇦 ON ICS4U / AB CSE3120手工追踪给定 Python 类代码片段的输出(预测一系列方法调用后每个print语句的输出)。🇨🇦 ON ICS4U / AB CSE3120 - Create a list of objects from the same class and use a
forloop to call a method on each one. Write code to find the object with the maximum attribute value. 🇨🇦 AB CSE3120 3.3 / ON ICS4U创建同一类的对象列表,用for循环对每个对象调用方法。编写代码找出属性值最大的对象。🇨🇦 AB CSE3120 3.3 / ON ICS4U - Distinguish mutators (setters) from accessors (getters) by name and purpose. Give an example of each from the
BankAccountclass. 🇨🇦 ON ICS4C B2.1按名称和目的区分修改器(setter)和访问器(getter)。从BankAccount类中各举一例。🇨🇦 ON ICS4C B2.1 - Write a subclass in Python that extends a parent class with
class Child(Parent):, callssuper().__init__(...), and adds at least one new attribute and one new method. 🇨🇦 ON ICS4U A2.2 / AB CSE3120 1.1.2用class 子类(父类):在 Python 中编写继承父类的子类,调用super().__init__(...),添加至少一个新属性和一个新方法。🇨🇦 ON ICS4U A2.2 / AB CSE3120 1.1.2 - State which Ontario course (ICS3U or ICS4U) teaches OOP and cite the verbatim expectation code that mentions encapsulation. 🇨🇦 ON ICS4U C1.2说明哪门安大略课程(ICS3U 还是 ICS4U)教授 OOP,并引用提到封装的逐字期望代码。🇨🇦 ON ICS4U C1.2
- State the Alberta CSE module code for OOP and its prerequisite chain (CSE1110 → CSE1120 → CSE2110 → CSE3120). Explain what "Advanced (3xxx)" means for the honors flag. 🇨🇦 AB CSE3120说明阿尔伯塔 OOP 的 CSE 模块代码及其前置链(CSE1110 → CSE1120 → CSE2110 → CSE3120)。解释"进阶(3xxx)"对荣誉标记意味着什么。🇨🇦 AB CSE3120
- Honors — ICS4U A2.2 / CSE3130 Explain method overriding (a subclass replaces a parent method) and polymorphism (parent-typed code works on subclass objects). Give a one-class example of each. 🇨🇦 ON ICS4U A2.2 / AB CSE3130荣誉 — ICS4U A2.2 / CSE3130 解释方法覆盖(子类替换父类方法)和多态(父类类型代码适用于子类对象)。各举一个单类示例。🇨🇦 ON ICS4U A2.2 / AB CSE3130
What This Feeds Into本单元的去向
OOP is the gateway to the AP CSA course. Everything in this guide — class definition, constructors, attributes, methods, encapsulation — maps directly to AP CSA Unit 3 (Class Creation) in Java. The Python syntax differs but the concepts are identical: class, instance, __init__ (Java: constructor), self.attr (Java: this.field), public/private access. The feeder link below goes directly to the AP CSA Class Creation guide.OOP 是进入 AP CSA 课程的门户。本指南中的所有内容——类的定义、构造函数、属性、方法、封装——直接对应 AP CSA 第 3 单元(Java 类的创建)。Python 语法不同但概念相同:类、实例、__init__(Java:构造函数)、self.attr(Java:this.field)、公有/私有访问。下方衔接链接直接指向 AP CSA 类创建指南。
AP CSA feeder link (confirmed in this repo).AP CSA 衔接链接(本仓库已确认)。
Ontario ICS4U and Alberta CSE3120 students who master this guide are well-prepared for the AP CSA Java OOP units. The conceptual vocabulary is the same; only the syntax changes. ICS4U A2.2 names "encapsulation, inheritance, method overloading, method overriding, polymorphism" — all topics developed in AP CSA Units 3–10. CSE3130 (OOP 2) extends further into UML-based design, directly mirroring AP CSA Unit 9 (Inheritance).掌握本指南的安大略 ICS4U 和阿尔伯塔 CSE3120 学生已为 AP CSA Java OOP 单元做好充分准备。概念词汇相同,只有语法不同。ICS4U A2.2 命名了"封装、继承、方法重载、方法覆盖、多态"——这些都是 AP CSA 第 3-10 单元发展的主题。CSE3130(OOP 2)进一步扩展到基于 UML 的设计,直接对应 AP CSA 第 9 单元(继承)。