本周目标
- 掌握类(Class) 和对象(Object) 的核心概念
- 理解
__init__ 构造方法和 self 的作用
一、从“面向过程”到“面向对象”的思维转变
之前我们一直在用面向过程的方式编程——把程序看作一系列按顺序执行的操作步骤。
而面向对象编程(OOP) 则把现实世界映射到代码中:用类(Class) 描述一类事物的“蓝图”,用对象(Object) 表示具体的实体。就像现实中“人”是一个抽象概念,而“张三”是一个具体的人一样。
OOP 在 AI 领域无处不在:
- PyTorch 中,你定义的每一个神经网络模型都是继承自
nn.Module 类的对象
💡 核心转变:面向过程关注“怎么做”(算法步骤),面向对象关注“谁来做”(数据和行为的主体)。
二、类与对象——从“图纸”到“实物”的构建
1. 什么是类?什么是对象?
类(Class) 就像一张建筑设计图纸——它定义了房子应该有什么结构(属性)和能做什么(方法),但图纸本身不是房子。
对象(Object) 就是根据这张图纸建造出来的真实房子——每栋房子都有具体的位置、面积、居住者,而且可以执行开门、关门等操作。
# 定义一个“狗”类(图纸)class Dog: # 属性(特征) def __init__(self, name, breed): self.name = name self.breed = breed # 方法(行为) def bark(self): print(f"{self.name} 汪汪叫!")# 创建对象(根据图纸建造实物)dog1 = Dog("旺财", "金毛") # 一个具体的狗dog2 = Dog("小黑", "泰迪") # 另一个具体的狗# 调用对象的方法dog1.bark() # 旺财 汪汪叫!dog2.bark() # 小黑 汪汪叫!
2. 类的定义语法
class 类名: """文档字符串(可选)""" def __init__(self, 参数1, 参数2, ...): """构造方法:创建对象时自动调用,用于初始化属性""" self.属性名1 = 参数1 self.属性名2 = 参数2 def 方法名(self, 其他参数): """普通方法:描述对象的行为""" # 可以通过 self 访问对象的属性 pass
⚠️ 命名规范:类名使用大驼峰命名法(如 Student、NeuralNetwork),而变量名和函数名使用小写加下划线(如 student_name、calculate_score)。
三、__init__ 与 self —— 面向对象的“灵魂”
1. __init__ 构造方法
__init__ 是 Python 类的构造方法,在创建对象时自动调用,用于初始化对象的属性。
class Student: def __init__(self, name, age, score): print(f"正在创建学生:{name}") self.name = name self.age = age self.score = score# 创建对象时,__init__ 自动执行s1 = Student("张三", 20, 95) # 输出:正在创建学生:张三s2 = Student("李四", 22, 88) # 输出:正在创建学生:李四
2. self —— 指向“我”自己
self 是 Python 类方法的第一个参数,代表当前对象本身。通过 self,方法可以访问和操作当前对象的属性和其他方法。
class Car: def __init__(self, brand, color): self.brand = brand # self.brand 是对象的属性,brand 是传入的参数 self.color = color self.mileage = 0 # 可以设置默认值 def drive(self, distance): self.mileage += distance # 通过 self 修改属性 print(f"{self.color}色的{self.brand}行驶了{distance}公里") def show_info(self): print(f"品牌:{self.brand},颜色:{self.color},里程:{self.mileage}公里")# 使用my_car = Car("特斯拉", "红色")my_car.drive(100) # 红色色的特斯拉行驶了100公里my_car.drive(50) # 红色色的特斯拉行驶了50公里my_car.show_info() # 品牌:特斯拉,颜色:红色,里程:150公里
⚠️ 新手常见误区:
- 在方法中忘记写
self 参数 → 调用时报错 missing 1 required positional argument - 在方法中访问属性时忘记加
self. → 会被当作局部变量处理,逻辑出错
四、类的属性和方法详解
1. 实例属性 vs 类属性
实例属性:属于每个对象自己的数据,通过 self.属性名 定义,每个对象独立。类属性:属于类本身的数据,所有对象共享,在类中直接定义。
class Employee: # 类属性(所有员工共享) company = "AI科技公司" total_employees = 0 def __init__(self, name, salary): # 实例属性(每个员工独有) self.name = name self.salary = salary Employee.total_employees += 1 # 每创建一个员工,总数+1# 访问类属性(可以通过类名,也可以通过实例)print(Employee.company) # AI科技公司e1 = Employee("张三", 10000)e2 = Employee("李四", 12000)print(e1.company) # AI科技公司(实例也可以访问类属性)print(Employee.total_employees) # 2
2. 实例方法 vs 类方法 vs 静态方法
class MathUtils: pi = 3.14159 # 类属性 def __init__(self, version): self.version = version # 实例属性 # 实例方法:最常用,通过 self 访问实例属性 def get_version(self): return self.version # 类方法:通过 cls 访问类属性,用 @classmethod 装饰 @classmethod def get_pi(cls): return cls.pi # 静态方法:不需要 self 或 cls,用 @staticmethod 装饰(只是一个普通函数放在类里) @staticmethod def add(a, b): return a + b# 调用utils = MathUtils("v1.0")print(utils.get_version()) # v1.0(实例方法)print(MathUtils.get_pi()) # 3.14159(类方法)print(MathUtils.add(3, 5)) # 8(静态方法)
💡 AI小贴士:在 AI 框架中,类方法常用于创建预训练模型(如 BertModel.from_pretrained()),静态方法常用于工具函数(如 torch.cat())。
五、封装 —— 让数据更安全
封装(Encapsulation) 是 OOP 的三大特性之一,指把数据和操作数据的方法绑定在一起,并隐藏内部实现细节,只暴露必要的接口。
1. 私有属性和方法(命名约定)
Python 通过命名约定来实现“私有”:
- _name(单下划线开头):保护属性,表示“不要直接访问”(只是约定,实际上仍可访问)
- __name(双下划线开头):私有属性,Python 会进行名称修饰(Name Mangling),防止被子类覆盖
class BankAccount: def __init__(self, owner, balance): self.owner = owner self.__balance = balance # 私有属性(双下划线) def deposit(self, amount): if amount > 0: self.__balance += amount print(f"存入 {amount},当前余额:{self.__balance}") def withdraw(self, amount): if 0 < amount <= self.__balance: self.__balance -= amount print(f"取出 {amount},当前余额:{self.__balance}") else: print("余额不足或金额无效") def get_balance(self): """通过公开方法获取余额(封装了内部实现)""" return self.__balanceaccount = BankAccount("张三", 1000)account.deposit(500) # 存入 500,当前余额:1500account.withdraw(200) # 取出 200,当前余额:1300# print(account.__balance) # ❌ AttributeError(私有属性不能直接访问)print(account.get_balance()) # 1300(通过公开方法访问)
💡 封装的价值:你可以随时修改 __balance 的存储方式(比如改为数据库存储),而使用 get_balance() 的代码完全不受影响——这就是“接口不变,实现可改”。
2. 使用 @property 实现优雅的访问控制
@property 装饰器可以把方法变成“属性”来访问,语法更优雅:
class Person: def __init__(self, name, age): self.name = name self._age = age # 受保护的属性 @property def age(self): """将 age 方法变成属性,通过 person.age 访问""" return self._age @age.setter def age(self, value): """通过 person.age = 新值 来设置,可以添加验证逻辑""" if value < 0 or value > 150: raise ValueError("年龄必须在 0-150 之间") self._age = valuep = Person("张三", 25)print(p.age) # 25(像访问属性一样,不用加括号)p.age = 26 # 像设置属性一样print(p.age) # 26# p.age = -5 # ❌ ValueError
六、 闲谈
python非常信任开发者,类中私有属性只是名称被改写了。
class BankAccount: def __init__(self, owner, balance): self.owner = owner self.__balance = balance # 私有属性(双下划线) def get_balance(self): """通过公开方法获取余额(封装了内部实现)""" return self.__balanceaccount = BankAccount("张三", 1000)# print(account.__balance) # ❌ AttributeError(私有属性不能直接访问)account._BankAccount__balance =999999999print(account.get_balance()) # 999999999(通过公开方法访问)
本周小结
本周我们正式进入面向对象编程的世界:
| |
|---|
| 类与对象 | 类是蓝图,对象是实例。用 class 类名: 定义,用 对象名 = 类名() 创建 |
__init__ | |
self | 代表当前对象,通过 self.属性 访问对象的数据 |
| 实例属性 vs 类属性 | |
| 实例方法 vs 类方法 vs 静态方法 | 分别用 self、@classmethod、@staticmethod 定义 |
| 封装 | 用 __属性 实现私有,用 @property 实现优雅的访问控制 |
| OOP 的价值 | |
下周预告:我们将继续深入面向对象编程,学习继承(Inheritance) 和多态(Polymorphism)——这是 OOP 的核心魅力所在,能让代码实现“一次编写,到处扩展”的效果!
面向对象编程是程序员思维的一次重要跃升——从“写代码”到“设计系统”。好好消化本周内容,它将影响你之后所有编程的思维方式! 🚀