Skip to content

Module 6: 面向对象编程基础 (OOP)

理解 df.method() 的秘密 —— 为什么数据科学需要 OOP


本章概览

如果你用过 Pandas,你已经在使用面向对象编程(OOP)了!每次调用 df.head()df.mean()model.fit(X, y),你都在与对象交互。本章将揭开 OOP 的神秘面纱,帮助你理解数据科学库的设计哲学,并学会创建自己的类。

重要提示:社科学生不需要深入学习 OOP,但要理解其基本概念,这样才能更好地使用 Pandas、Scikit-learn 等库。


学习目标

学完本章后,你将能够:

  • 理解类(Class)与对象(Object)的概念
  • 知道为什么 Pandas、Scikit-learn 使用 OOP
  • 理解 df.method()df.attribute 的含义
  • 创建简单的类来组织代码
  • 使用特殊方法(__init____str____len__)
  • 对比面向对象 vs 函数式编程
  • 构建数据分析流水线类

章节内容

01 - 面向对象编程入门

核心问题: 为什么社科学生要学 OOP?

核心内容:

  • 你已经在用 OOP 了:
    python
    df = pd.DataFrame({'age': [25, 30, 35]})
    result = df.mean()  # df 是对象,mean() 是方法
  • OOP 核心概念:
    • 对象(Object):数据 + 方法的集合
    • 类(Class):对象的模板/蓝图
    • 方法(Method):对象的函数
    • 属性(Attribute):对象的数据
  • 为什么需要 OOP:数据和方法绑定在一起,代码更有组织性
  • 理解 Pandas 的 OOP 设计:
    python
    df.head()      # 方法调用
    df.shape       # 属性访问
    df.to_csv()    # 方法调用
  • 对比 Python(面向对象) vs R(函数式):
    • Python: df.mean()
    • R: mean(df$x)
  • 创建第一个类:学生类、调查响应类
  • 面向对象 vs 函数式编程的选择

为什么重要?

  • 理解 Pandas、Scikit-learn 的使用方式
  • 知道何时用类、何时用函数
  • 让代码更易维护和复用

实际应用:

python
class SurveyResponse:
    def __init__(self, id, age, income):
        self.id = id
        self.age = age
        self.income = income
    
    def is_valid(self):
        return 18 <= self.age <= 100 and self.income >= 0
    
    def income_category(self):
        if self.income < 50000:
            return "低收入"
        elif self.income < 100000:
            return "中收入"
        else:
            return "高收入"

resp = SurveyResponse(1001, 30, 75000)
print(resp.is_valid())         # True
print(resp.income_category())  # 中收入

02 - 类与对象详解

核心问题: 如何创建和使用类?

核心内容:

  • 类的完整结构:
    python
    class ClassName:
        class_variable = "共享数据"  # 类属性
        
        def __init__(self, param):
            self.param = param      # 实例属性
        
        def method(self):           # 实例方法
            return self.param
  • 实例属性 vs 类属性:
    • 实例属性:每个对象独有(self.name)
    • 类属性:所有对象共享(ClassName.variable)
  • 常用特殊方法(魔法方法):
    • __init__:构造函数(创建对象时调用)
    • __str__:字符串表示(用于 print())
    • __repr__:开发者表示(用于调试)
    • __len__:长度(用于 len())
  • @property 装饰器:将方法转为属性
    python
    @property
    def net_income(self):
        return self.income * 0.75
    
    # 使用:resp.net_income(无需括号)
  • 封装:公有 vs 私有:
    • 公有:self.balance
    • 约定私有:self._transactions(单下划线)
    • 真正私有:self.__pin(双下划线)

实战案例:

python
class Student:
    school_name = "北京大学"  # 类属性
    
    def __init__(self, id, name, major, gpa=0.0):
        self.id = id
        self.name = name
        self.major = major
        self.gpa = gpa
        self.courses = []
    
    def enroll_course(self, name, credits):
        self.courses.append({'name': name, 'credits': credits})
    
    def get_total_credits(self):
        return sum(c['credits'] for c in self.courses)
    
    def __str__(self):
        return f"{self.name} ({self.major}, GPA: {self.gpa})"

alice = Student(2024001, "Alice", "Economics", 3.8)
alice.enroll_course("Microeconomics", 4)
print(alice)  # Alice (Economics, GPA: 3.8)

03 - OOP 在数据科学中的应用

核心问题: 为什么数据科学库都使用 OOP?

核心内容:

  • Pandas 的 OOP 设计:
    • DataFrame 和 Series 都是对象
    • 链式调用的优势:
      python
      result = (df
          .query('age > 30')
          .assign(log_income=lambda x: np.log(x['income']))
          .sort_values('income')
          .reset_index(drop=True)
      )
  • Scikit-learn 的 OOP 设计:
    • 统一的 API:fit()predict()
    python
    model = LinearRegression()
    model.fit(X, y)
    predictions = model.predict(X_test)
    print(model.coef_, model.intercept_)  # 访问属性
  • Statsmodels 的 OOP 设计:
    python
    model = smf.ols('income ~ education + age', data=df)
    results = model.fit()
    print(results.summary(), results.rsquared)
  • 创建自己的数据科学类:
    • 简单线性回归类(教学用)
    • 数据处理流水线类
  • OOP 最佳实践:
    • 设计可链式调用的方法(返回 self)
    • 使用属性存储元数据(is_fitted, n_features)
    • 实现 __repr__ 便于调试

实战案例:数据流水线类:

python
class DataPipeline:
    def __init__(self, df):
        self.df = df.copy()
        self.steps = []
    
    def remove_missing(self):
        self.df = self.df.dropna()
        self.steps.append("remove_missing")
        return self  # 支持链式调用
    
    def filter_age(self, min_age, max_age):
        self.df = self.df[(self.df['age'] >= min_age) & 
                          (self.df['age'] <= max_age)]
        self.steps.append(f"filter_age({min_age}, {max_age})")
        return self
    
    def get_result(self):
        return self.df

# 链式调用
result = (DataPipeline(df)
    .remove_missing()
    .filter_age(18, 65)
    .get_result()
)

面向对象 vs 函数式编程

维度函数式编程面向对象编程
组织方式函数 + 数据分离数据和方法绑定
典型语言R, MATLABPython, Java
适用场景简单脚本、数据分析大型项目、库开发
代码风格mean(df$x)df['x'].mean()

函数式风格(R 风格)

python
# 数据和函数分离
def calculate_tax(income, rate):
    return income * rate

def is_valid(age):
    return age >= 18

income = 75000
tax = calculate_tax(income, 0.25)

面向对象风格(Python 风格)

python
# 数据和方法绑定
class Respondent:
    def __init__(self, income, age):
        self.income = income
        self.age = age
    
    def calculate_tax(self, rate=0.25):
        return self.income * rate
    
    def is_valid(self):
        return self.age >= 18

resp = Respondent(75000, 30)
tax = resp.calculate_tax()

如何学习本章?

学习路线

第 1 天(2小时): OOP 入门

  • 阅读 01 - 面向对象编程入门
  • 理解类、对象、方法、属性的概念
  • 创建第一个类(Student 或 SurveyResponse)

第 2 天(3小时): 类与对象详解

  • 阅读 02 - 类与对象详解
  • 学习特殊方法(__init____str____len__)
  • 实践 @property 装饰器

第 3 天(2小时): 数据科学中的 OOP

  • 阅读 03 - OOP 在数据科学中的应用
  • 理解 Pandas、Scikit-learn 的 OOP 设计
  • 创建简单的数据流水线类

总时间: 7 小时(1 周)

最小化学习路径

对于社科学生,OOP 不是核心技能,优先级如下:

必学(理解别人的代码,4小时):

  • 01 - OOP 入门(理解 Pandas 的 OOP 设计)
  • 03 - 数据科学应用(理解 Scikit-learn 的使用)
  • 知道 df.method()df.attribute 的区别

选学(自己写类,3小时):

  • 02 - 类与对象详解
  • 特殊方法、@property
  • 创建自己的类

可跳过(高级主题):

  • 类方法、静态方法
  • 继承、多态
  • 复杂的封装设计

学习建议

  1. 理解优先于创建

    • 先理解 Pandas、Scikit-learn 的 OOP 用法
    • 再考虑是否需要自己创建类
    • 大多数数据分析用函数就够了
  2. 从使用到创建

    python
    # 第一步:会用别人的类
    df = pd.DataFrame({'x': [1, 2, 3]})
    df.mean()
    
    # 第二步:理解原理
    # DataFrame 是类,df 是对象,mean() 是方法
    
    # 第三步:创建自己的类(可选)
    class MyDataFrame:
        def __init__(self, data):
            self.data = data
  3. 何时需要创建类?

    • 需要封装复杂的数据 + 操作
    • 需要复用的组件(数据流水线、自定义模型)
    • 大型项目需要组织代码
    • 简单脚本、一次性分析(用函数)
  4. 对比学习

    • Python 的 OOP 风格:数据和方法绑定
    • R 的函数式风格:数据和函数分离
    • Stata:几乎不用 OOP(全是命令)

常见问题

Q: 我必须学 OOP 吗?能不能跳过? A: 不能完全跳过。你不需要深入学习,但要理解基本概念,否则无法理解 Pandas、Scikit-learn 的文档。建议:理解 df.method() 的含义即可,不必自己写复杂的类。

Q: 为什么 Python 用 OOP,R 用函数式? A:

  • Python 是通用编程语言,OOP 更适合大型项目
  • R 是统计语言,函数式更符合数学习惯
  • 两者都能完成数据分析,只是风格不同

Q: df.head()head(df) 有什么区别? A:

  • df.head():OOP 风格,DataFrame 对象调用自己的方法
  • head(df):函数式风格,函数接受 DataFrame 作为参数
  • Python 偏好前者,R 偏好后者

Q: 什么是 self? A: self 代表对象自己。当你调用 resp.is_valid() 时,Python 自动将 resp 传给 self,这样方法就能访问对象的属性。

Q: 我什么时候需要自己创建类? A:

  • 需要:构建可复用的数据流水线、封装复杂分析逻辑、大型项目
  • 不需要:简单脚本、一次性分析、探索性数据分析

Q: OOP 会让代码更快吗? A: 不会。OOP 的优势在于组织性可维护性,而非性能。对于数据分析,性能主要取决于算法和库(NumPy、Pandas),而非 OOP。


下一步

完成本章后,你将掌握:

  • OOP 的基本概念(类、对象、方法、属性)
  • 理解 Pandas、Scikit-learn 的 OOP 设计
  • 知道何时用类、何时用函数
  • 能创建简单的类来组织代码

Module 7 中,我们将学习文件 I/O,学会读写 CSV、Excel、JSON、Stata 等数据文件。

Module 9 中,我们将深入学习 NumPy、Pandas、Matplotlib 等数据科学核心库。

OOP 不是社科学生的核心技能,理解即可!继续前进!


快速链接

基于 MIT 许可证发布。内容版权归作者所有。