Python 面向对象入门:从类与实例到封装继承多态实战

发布时间:2026/9/18 18:23:58
Python 面向对象入门:从类与实例到封装继承多态实战 简介这份Python基础入门系列中的面向对象编程专题PPT课件共64页面向零基础到进阶的Python学习者帮助梳理类、对象、封装、继承与多态等核心概念。压缩包仅含1个pptx文件大小约962KB页面图文并茂配合代码示例与概念对照适合课堂讲解、自学复盘或备课参考。课件从面向过程与面向对象的差异切入逐步展开类的定义、实例化、属性与方法、成员变量、超类与子类关系以及多态在统一接口中的体现并联系列表、字典、函数与算法等前置知识同时点明数据与功能复用、灵活性和扩展性等设计考量。已有282人学习可作为系统掌握Python编程思想、理解“一切皆对象”与提升代码组织能力的入门材料。通过典型Dog类实例读者能直观看到数据与行为如何组织为对象从而把封装、继承、多态等抽象原则落到可运行代码中。1. 从一份 64 页 PPT 说起为什么 Python 入门者卡在面向对象这一关很多人学 Python 的顺序是语法、循环、列表字典、函数一路顺畅到「类」这一章突然卡住。变量还能理解为贴标签函数还能理解为一段可复用的代码块但class、self、实例、继承这些词一上来前面建立的直觉全不管用了。我见过不少人函数写得挺溜一让设计类的结构就发懵最后写出来的代码是「披着类外皮的面向过程」——一个类里塞一堆没有状态的方法或者满屏def __init__赋值却没有任何行为封装。这份 64 页的课件恰好是给这个卡点准备的。它从「程序 数据结构 算法」这条老公式切进去把「以算法为核心」和「以数据为核心」两种思路摆在一起对比再自然过渡到类、实例、封装、继承、多态三条原则。对刚过完函数和模块、准备进入工程化写法的入门者来说这是从「能跑」到「能维护」的分水岭。这篇文章不复述 PPT 目录而是把它讲的那套概念落成能敲、能调、能排错的代码和判断标准。2. 面向过程与面向对象的选型先看清数据和算法谁是主角2.1 两种范型的差别不在语法在组织代码的出发点课件里有句话点得很准程序 算法 数据代码可以选择以算法为核心也可以选择以数据为核心。这两种选择直接决定你的函数长什么样。以算法为核心写出来的代码围绕「正在发生什么」。比如处理一批学生成绩# 面向过程写法数据是散的函数围着处理逻辑转 students [ {name: bili, score: 88}, {name: amy, score: 95}, ] def average(records): return sum(r[score] for r in records) / len(records) def top(records, n1): return sorted(records, keylambda r: r[score], reverseTrue)[:n]这里students只是一个列表average和top谁都能传进来乱改字典的 key 拼错在运行时才炸。数据本身没有任何约束全靠开发者自觉。以数据为核心则是另一套写法围绕「将影响谁」来组织。同样的成绩问题改写成数据持有自己的行为class ScoreSheet: def __init__(self, recordsNone): # 私有约定外部不要直接碰这个列表 self._records list(records or []) def add(self, name, score): if not 0 score 100: raise ValueError(f分数越界: {score}) self._records.append({name: name, score: score}) def average(self): if not self._records: return 0 return sum(r[score] for r in self._records) / len(self._records) def top(self, n1): return sorted(self._records, keylambda r: r[score], reverseTrue)[:n]比较一下差异校验规则、空列表处理、排序逻辑全都收进了类里调用方只能通过add改数据分数越界在写入那一刻就报错而不是等到统计时才发现负数混进去了。这就是课件说的「用数据控制对代码的访问」。2.2 什么时候该上类什么时候函数就够了不是所有场景都值得写类。判断标准其实很朴素如果一组数据总是和一组操作绑在一起出现且这些操作需要维护某种内部一致性比如校验、缓存、状态机就适合封装成类。反过来无状态的纯计算——字符串格式化、数学变换、一次性的数据清洗——写成函数更直接。我一般用下面这张表来快速判断判断维度倾向函数倾向类是否有需要维护的状态无有且状态间有约束操作是否围绕同一份数据否是是否需要多个实现共享接口否是用继承/多态复用方式复制调用继承或组合典型例子abs、字符串切片连接池、订单、解析器看完这张表你会发现「面向对象」不是把每个函数都包一层类而是当数据确实需要被保护、被扩展、被多态替换时才引入。课件强调「封装、继承、多态」是原则而非教条原因就在这里。3. 类与实例的落地从 Dog 类到 self、属性和方法3.1 类的抽象与实例的具象是两回事课件用 Dog 打比方类是一类事物的抽象集合实例是有血有肉的具体存在。抽象层面狗都有名字、年龄、品种都会叫和跑具象层面你的狗叫 bili1 岁大型犬还会跳起来拣球。落到代码上class Dog: # 类属性所有狗共享留意它的坑 species Canis lupus familiaris def __init__(self, name, age, breed): # 实例属性每条狗各自持有 self.name name self.age age self.breed breed self._tricks [] # 约定为内部使用 def bark(self): return f{self.name} 在叫 def run(self): return f{self.name} 跑起来了 def learn(self, trick): self._tricks.append(trick) return self.tricks property def tricks(self): # 只读视图外部改不了原列表 return tuple(self._tricks)实例化很简单my_dog Dog(bili, 1, 大型犬) print(my_dog.bark()) # bili 在叫 my_dog.learn(拣球) print(my_dog.tricks) # (拣球,)关键点在self。它不是关键字只是约定俗成的第一个参数名代表「当前这个实例」。my_dog.bark()调用时Python 自动把my_dog传进self所以你才不用手写参数。新手最常犯的错是在方法里写name而不是self.name前者会去全局或类作用域找找不到就NameError。提示类属性species所有实例共享用self.species xxx赋值不会改类属性而是给这个实例新增了一个同名实例属性从此它和类属性分道扬镳。要改共享值得用Dog.species xxx但通常不建议这么写。3.2 三类方法别混用实例方法、类方法、静态方法很多人学完__init__就以为方法都一样其实 Python 有三类用错地方代码会别扭class Dog: population 0 # 类属性统计总数 def __init__(self, name): self.name name Dog.population 1 def bark(self): # 实例方法需要 self return f{self.name} 在叫 classmethod def from_string(cls, text): # 类方法需要 cls常用于备选构造器 return cls(text.strip().title()) staticmethod def is_valid_name(text): # 静态方法不碰 self 也不碰 cls return isinstance(text, str) and text.strip() ! 实例方法要读写实例状态必须带self比如bark。类方法操作类本身或做备选构造器第一个参数是cls。上面Dog.from_string(bili)返回一个Dog实例比裸调__init__语义更清楚。静态方法纯工具逻辑和类状态无关放进来只是为了归属清晰比如Dog.is_valid_name(字符串)。3.3 封装在 Python 里靠约定而非强制课件问了一句「list.pop()是怎么实现的」答案是有意不让你知道。Python 没有private关键字而是用命名约定_name表示内部使用__name会触发名称改写name mangling外部访问得写成_ClassName__name。真实项目里_单下划线就够了双下划线留给确实不想被继承覆盖的场合。class Account: def __init__(self, balance0): self._balance balance # 约定别直接从外部改 property def balance(self): return self._balance def deposit(self, amount): if amount 0: raise ValueError(存款必须为正) self._balance amount外部只能读account.balance想加钱必须走deposit校验跑不掉。这就是「隐藏实现细节、提供对外接口」的最小落地。4. 继承与多态实战按层分类、复写方法与统一接口4.1 继承解决的是「按层分类」而不是「代码少写几行」课件画过一张动物到具体犬种的层级图从动物、哺乳动物、犬科一路细到金毛、拉布拉多。继承的意义是让子类自动获得祖先的全部属性从而表达「是一种」的关系。class Animal: def __init__(self, name): self.name name def make_sound(self): return 某种声音 class Dog(Animal): def __init__(self, name, breed): super().__init__(name) # 调用父类构造别漏 self self.breed breed def make_sound(self): return 汪汪 class Cat(Animal): def make_sound(self): return 喵喵super().__init__(name)是关键写法。它按 MRO方法解析顺序找下一个合适的父类构造器比写死Animal.__init__(self, name)更安全多重继承时尤其明显。子类复写make_sound后Dog走自己的实现没复写的方法则继续用父类的。注意继承是「是一种」is-a关系。如果两个类只是有部分逻辑重合用组合把一个对象当属性持有比继承更合适。滥继承最容易导致改父类伤一片子类。4.2 多态同一个接口不同的实现课件把多态描述为「一组相关的动作共享一个通用接口」。上面Dog和Cat都有make_sound这就是同一接口的不同实现。写一段不关心具体类型的代码试试def chorus(animals): # 不判断类型只依赖 make_sound 这个接口 return [f{a.name}: {a.make_sound()} for a in animals] print(chorus([Dog(bili, 大型犬), Cat(kitty)])) # [bili: 汪汪, kitty: 喵喵]函数里没有isinstance判断传进来什么动物就调它自己的make_sound。以后新增Bird类chorus一行都不用改。这就是多态降低复杂性的实际收益——扩展靠新增类而不是修改分发逻辑。Python 的多态是隐式、动态的俗称「鸭子类型」只要对象有需要的方法就能被当成某种角色用。这在工程上带来灵活性代价是接口约定有时不够显式所以规模大时可以考虑抽象基类来约束。4.3 用抽象基类把接口约定显式化如果希望子类必须实现某个方法可以用abcfrom abc import ABC, abstractmethod class Shape(ABC): abstractmethod def area(self): ... class Circle(Shape): def __init__(self, r): self.r r def area(self): return 3.14159 * self.r ** 2 # Shape() # 直接实例化会报 TypeErrorShape不能被实例化Circle不实现area也会报错。这比靠注释约定强得多团队协作时尤其有用。5. 把 OOP 用到真实任务里一个可扩展的数据处理小框架5.1 从规则里抽象出类而不是给每个规则写一个函数前面章节铺完了类、继承、多态这一节把它们拧到一起做一个能扩展的小场景清洗一批文本记录。假设需求是「按规则过滤并统计」。如果你把每条规则写成独立函数调用方会变成一串if用类来组织扩展只需加子类。from abc import ABC, abstractmethod class Rule(ABC): abstractmethod def check(self, record): 返回 True 表示记录保留 ... class NotEmpty(Rule): def check(self, record): return bool(record.strip()) class MaxLength(Rule): def __init__(self, limit): self.limit limit def check(self, record): return len(record) self.limit class Cleaner: def __init__(self, rules): self.rules list(rules) def process(self, records): kept, dropped [], 0 for r in records: if all(rule.check(r) for rule in self.rules): kept.append(r.strip()) else: dropped 1 return kept, dropped cleaner Cleaner([NotEmpty(), MaxLength(20)]) print(cleaner.process([ hello , , x * 50])) # ([hello], 2)Cleaner只依赖Rule的check接口新增规则加一个子类就行process不用动。这正是多态在业务代码里的典型价值。5.2 上线前先自检几个高频踩坑点写完类别急着跑我一般过一遍下面这几项检查项典型症状修法可变默认参数多个实例共享同一个列表默认写None在__init__里list(x or [])忘调super().__init__父类属性缺失AttributeError子类构造第一行补上混用类/实例属性改一个实例影响了所有实例需要独立的属性放进__init__self拼写或漏写方法内NameError方法内访问实例一律self.x覆写双下划线方法出错运算符行为异常查__eq__、__repr__等是否成对实现可变默认参数那个坑特别隐蔽class Bag: def __init__(self, items[]): # 错误示范 self.items items a, b Bag(), Bag() a.items.append(x) print(b.items) # [x]被误伤了 class Bag: def __init__(self, itemsNone): # 正确写法 self.items list(items) if items else []默认参数在函数定义时只求值一次[]被所有实例共享。改用None哨兵每次构造新建列表问题消失。5.3 用验证脚本确认继承和多态真的生效光看代码不放心写个最小验证脚本跑一遍if __name__ __main__: d Dog(bili, 大型犬) c Cat(kitty) assert d.make_sound() 汪汪 assert c.make_sound() 喵喵 assert isinstance(d, Animal) # Dog 确实是一种 Animal assert issubclass(Dog, Animal) assert Dog.__mro__[0] is Dog # 方法解析顺序第一个是自己 cleaned, dropped Cleaner([NotEmpty(), MaxLength(5)]).process([ok, ]) assert cleaned [ok] and dropped 1 print(全部通过)__mro__打印出来是(Dog, Animal, object)多重继承时它就是 Python 查找方法的路线图。用断言把这些关系固定下来重构父类时才敢放手改。6. 进阶技巧让类写得更省心的几个内置方法课件最后落到「类由数据和方法组成」但没有展开一点Python 自带一批双下划线方法dunder实现它们能让你的类用起来跟内置类型一样自然。这不是炫技是把封装做彻底。class Vector: def __init__(self, x, y): self.x, self.y x, y def __add__(self, other): return Vector(self.x other.x, self.y other.y) def __eq__(self, other): return (self.x, self.y) (other.x, other.y) def __repr__(self): return fVector({self.x}, {self.y}) def __len__(self): return 2 v Vector(1, 2) Vector(3, 4) print(v) # Vector(4, 6) print(v Vector(4, 6)) # True__add__让对象支持__eq__决定相等语义__repr__影响调试打印__len__接上len()。实现它们之后你的类和内置类型的用法就统一了调用方不用记特殊 API。还有一组和属性访问相关的方法排查「属性从哪来」时特别管用class Proxy: def __init__(self, data): self._data data def __getattr__(self, name): # 仅当正常查找失败时才触发 return getattr(self._data, name) def __str__(self): return fProxy{self._data}__getattr__只在属性找不到时兜底这点常和__getattribute__每次访问都触发搞混。前者适合做代理转发后者改动风险大入门阶段先别碰。最后一个实用习惯写完一个类用dir(obj)和vars(obj)各扫一眼。vars给出实例自己的属性字典能一眼看出哪些是实例独有的、哪些来自类。配合__mro__继承链上的属性来源就全透明了调试继承相关 bug 时比打断点更快。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询