小白python入门 - 17. Python面向对象编程入门

发布时间:2026/7/24 22:35:59
小白python入门 - 17. Python面向对象编程入门 面向对象编程Object-Oriented Programming, OOP是一种被广泛采用的编程范式。所谓编程范式本质上就是程序设计的方法论它定义了程序员如何理解程序结构以及编写代码的核心方式。在之前的课程中我们提到“程序是指令的集合”程序运行时语句被转化为指令由CPU执行。为了简化设计我们引入了函数的概念——将相对独立且重复使用的代码封装成函数在需要时调用即可。当单个函数变得过于复杂臃肿时我们又能将其进一步拆分为多个子函数以此降低系统复杂度。细心的你可能已经发现传统编程方式要求开发者遵循计算机的工作逻辑来编写指令控制机器。然而计算机的底层运作模式与人类的自然思维方式存在显著差异。若编程必须完全摒弃人类的思维习惯去迁就机器其过程难免会丧失许多乐趣。需要澄清的是我们并非否定这种方式本身但当面对复杂系统开发时严格遵循计算机思维编码会导致代码结构异常复杂使得开发与维护工作都变得异常困难。随着软件复杂性的激增编写正确可靠的代码已成为一项艰巨挑战这也印证了许多人的观点——“软件开发是人类活动中最为复杂的领域之一”。如何用程序有效地描述复杂系统、解决复杂问题成为每位开发者必须直面的核心命题。诞生于上世纪70年代的Smalltalk语言为开发者带来了曙光因为它引入了一种革命性的新范式面向对象编程。在OOP的世界里程序中的数据及其操作函数被组织成一个逻辑整体称为对象。对象能够接收消息解决问题的方式转变为创建对象并向它们发送各种消息。通过这种消息传递机制程序中的多个对象得以协同工作从而构建出能够应对现实世界复杂性的系统。当然OOP的雏形可以追溯至更早的Simula语言但这并非我们讨论的重点。说明今天我们使用的很多高级程序设计语言都支持面向对象编程但是面向对象编程也不是解决软件开发中所有问题的“银弹”或者说在软件开发这个行业目前还没有所谓的“银弹”。关于这个问题大家可以参考 IBM360 系统之父弗雷德里克·布鲁克斯所发表的论文《没有银弹软件工程的本质性与附属性工作》或软件工程的经典著作《人月神话》一书。面向对象介绍面向对象编程OOP是一种基于“对象”Objects概念的强大编程范式它将软件系统视为一系列相互作用对象的集合。每个对象都是一个独立的实体封装了特定的数据称为属性或状态以及操作这些数据的方法称为行为。OOP的核心思想在于通过以下几个关键特性来提升软件的结构性、可维护性和可重用性封装Encapsulation 将数据和对数据的操作捆绑在一个单元即对象内部并对外隐藏具体的实现细节。对象通过定义清晰的接口方法与外界交互外部代码无需了解内部运作机制。这有效保护了数据的完整性降低了模块间的耦合度。继承Inheritance 允许创建新的类称为子类或派生类基于现有类称为父类、基类或超类进行定义。子类自动继承父类的属性和方法并可以添加自己特有的属性或方法或重写继承来的方法以实现特定行为。这促进了代码的重用建立了类之间的层次关系is-a关系并支持多态的实现。多态Polymorphism 指同一个接口通常是方法名可以作用于不同的对象并呈现出不同的行为。这意味着程序可以处理不同类型的对象而无需关心其具体类型只需知道它们支持某个共同接口即可。多态通常通过继承子类重写父类方法或接口来实现极大地增强了代码的灵活性和可扩展性。在OOP中类Class扮演着“蓝图”或“模板”的角色它定义了某一类对象共有的属性和方法。而对象Object则是类的一个具体实例Instance是程序运行时在内存中实际创建并操作的实体。通过抽象出现实世界或问题域中的关键概念并将其建模为类和对象OOP能。够更自然、更有效地构建复杂、模块化和易于演进的软件系统。在面向对象编程的世界中一切皆为对象对象都有属性和行为每个对象都是独一无二的而且对象一定属于某个类。对象的属性是对象的静态特征对象的行为是对象的动态特征。按照上面的说法如果我们把拥有共同特征的对象的属性和行为都抽取出来就可以定义出一个类。定义类在 Python 语言中我们可以使用class关键字加上类名来定义类通过缩进我们可以确定类的代码块就如同定义函数那样。在类的代码块中我们需要写一些函数我们说过类是一个抽象概念那么这些函数就是我们对一类对象共同的动态特征的提取。写在类里面的函数我们通常称之为方法方法就是对象的行为也就是对象可以接收的消息。方法的第一个参数通常都是self它代表了接收这个消息的对象本身。classStudent:defstudy(self,course_name):print(f学生正在学习{course_name}.)defplay(self):print(f学生正在玩游戏.)创建和使用对象在我们定义好一个类之后可以使用构造器语法来创建对象代码如下所示。stu1Student()stu2Student()print(stu1)# __main__.Student object at 0x10ad5ac50print(stu2)# __main__.Student object at 0x10ad5acd0print(hex(id(stu1)),hex(id(stu2)))# 0x10ad5ac50 0x10ad5acd0在类的名字后跟上圆括号就是所谓的构造器语法上面的代码创建了两个学生对象一个赋值给变量stu1一个赋值给变量stu2。当我们用print函数打印stu1和stu2两个变量时我们会看到输出了对象在内存中的地址十六进制形式跟我们用id函数查看对象标识获得的值是相同的。现在我们可以告诉大家我们定义的变量其实保存的是一个对象在内存中的逻辑地址位置通过这个逻辑地址我们就可以在内存中找到这个对象。所以stu3 stu2这样的赋值语句并没有创建新的对象只是用一个新的变量保存了已有对象的地址。接下来我们尝试给对象发消息即调用对象的方法。刚才的Student类中我们定义了study和play两个方法两个方法的第一个参数self代表了接收消息的学生对象study方法的第二个参数是学习的课程名称。Python中给对象发消息有两种方式请看下面的代码。# 通过“类.方法”调用方法# 第一个参数是接收消息的对象# 第二个参数是学习的课程名称Student.study(stu1,Python程序设计)# 学生正在学习Python程序设计.# 通过“对象.方法”调用方法# 点前面的对象就是接收消息的对象# 只需要传入第二个参数课程名称stu1.study(Python程序设计)# 学生正在学习Python程序设计.Student.play(stu2)# 学生正在玩游戏.stu2.play()# 学生正在玩游戏.初始化方法大家可能已经注意到了刚才我们创建的学生对象只有行为没有属性如果要给学生对象定义属性我们可以修改Student类为其添加一个名为__init__的方法。在我们调用Student类的构造器创建对象时首先会在内存中获得保存学生对象所需的内存空间然后通过自动执行__init__方法完成对内存的初始化操作也就是把数据放到内存空间中。所以我们可以通过给Student类添加__init__方法的方式为学生对象指定属性同时完成对属性赋初始值的操作正因如此__init__方法通常也被称为初始化方法。我们对上面的Student类稍作修改给学生对象添加name姓名和age年龄两个属性。classStudent:学生def__init__(self,name,age):初始化方法self.namename self.ageagedefstudy(self,course_name):学习print(f{self.name}正在学习{course_name}.)defplay(self):玩耍print(f{self.name}正在玩游戏.)修改刚才创建对象和给对象发消息的代码重新执行一次看看程序的执行结果有什么变化。# 调用Student类的构造器创建对象并传入初始化参数stu1Student(骆昊,44)stu2Student(王大锤,25)stu1.study(Python程序设计)# 骆昊正在学习Python程序设计.stu2.play()# 王大锤正在玩游戏.总结面向对象编程有三大支柱就是我们之前给大家划重点的时候圈出的三个词封装、继承和多态。后面两个概念在下一节课中会详细说明这里我们先说一下什么是封装。我自己对封装的理解是隐藏一切可以隐藏的实现细节只向外界暴露简单的调用接口。我们在类中定义的对象方法其实就是一种封装这种封装可以让我们在创建对象之后只需要给对象发送一个消息就可以执行方法中的代码也就是说我们在只知道方法的名字和参数方法的外部视图不知道方法内部实现细节方法的内部视图的情况下就完成了对方法的使用。举一个例子假如要控制一个机器人帮我倒杯水如果不使用面向对象编程不做任何的封装那么就需要向这个机器人发出一系列的指令如站起来、向左转、向前走5步、拿起面前的水杯、向后转、向前走10步、弯腰、放下水杯、按下出水按钮、等待10秒、松开出水按钮、拿起水杯、向右转、向前走5步、放下水杯等才能完成这个简单的操作想想都觉得麻烦。按照面向对象编程的思想我们可以将倒水的操作封装到机器人的一个方法中当需要机器人帮我们倒水的时候只需要向机器人对象发出倒水的消息就可以了这样做不是更好吗在很多场景下面向对象编程其实就是一个三步走的问题。第一步定义类第二步创建对象第三步给对象发消息。当然有的时候我们是不需要第一步的因为我们想用的类可能已经存在了。之前我们说过Python内置的list、set、dict其实都是类如果要创建列表、集合、字典对象我们就不用自定义类了。当然有的类并不是 Python 标准库中直接提供的它可能来自于第三方的代码如何安装和使用三方代码在后续课程中会进行讨论。在某些特殊的场景中我们会用到名为“内置对象”的对象所谓“内置对象”就是说上面三步走的第一步和第二步都不需要了因为类已经存在而且对象已然创建过了直接向对象发消息就可以了这也就是我们常说的“开箱即用”。后记对于初学者来说可能理解这三个概念比较困难大家一定要多动手写代码实践从实战中理解面向对象的三个支柱。我在给新员工上课的时候常常以马云老师为例给大家讲解面向对象。封装我们看到马云老师知道其身上的特征有钱创建了阿里巴巴等等。类定义我们也要追求简单见名知意。继承大家为什么要叫马爸爸就是为了能花马老师的钱嘛多态马老师的所有特征我们都需要继承吗要继承马老师的颜值吗要继承马老师对钱不感兴趣的特征吗我们可以选择想要的特征进行继承不需要的特征可以通过多态修改。