当前位置: 首页 > news >正文

Python快速入门专业版(四十四):Python面向对象基础:类与对象的创建与使用(核心概念解析)

在这里插入图片描述

目录

  • 一、面向对象核心概念:从“现实世界”到“代码世界”
    • 1. 类(Class):抽象的模板
    • 2. 对象(Object):类的实例
    • 3. 面向对象三大特性
  • 二、类的定义:设计“模板”的语法
    • 1. 类的基本语法
      • 关键组件解析:
    • 2. 案例:定义`Car`类
  • 三、对象的创建与使用:从“模板”到“具体事物”
    • 1. 创建对象(实例化)
    • 2. 访问属性(类属性与实例属性)
    • 3. 调用方法
  • 四、深入理解`self`:对象的“身份标识”
    • 1. `self`的本质:不是“关键字”,是“约定”
    • 2. `self`的核心作用:关联“方法”与“对象”
  • 五、对比:面向过程 vs 面向对象
    • 1. 面向过程实现:以“步骤”为核心
    • 2. 面向对象实现:以“对象”为核心
  • 六、实战案例:汽车管理系统(面向对象版)
  • 七、常见问题与注意事项
  • 八、总结

在编程领域,有两种主流的编程范式:面向过程(Procedure-Oriented)和面向对象(Object-Oriented,简称OOP)。面向过程以“步骤”为核心,适合简单任务;而面向对象以“对象”为核心,通过封装、继承、多态三大特性,更适合复杂项目的开发与维护,是Python开发中不可或缺的思想。
本文将从面向对象的核心概念入手,详解类与对象的定义、创建与使用,通过“汽车类”案例演示属性与方法的设计,并对比面向过程与面向对象的逻辑差异,帮助你建立面向对象的编程思维。

一、面向对象核心概念:从“现实世界”到“代码世界”

面向对象的思想源于对现实世界的抽象——现实中的每个事物(如汽车、手机、人)都可以看作“对象”,而具有相同特征和行为的对象可以归为一个“类”。

1. 类(Class):抽象的模板

类是对同一类事物的共同特征与行为的抽象描述,相当于一个“模板”。例如:

  • “汽车”是一个类:它描述了所有汽车的共同特征(品牌、颜色、排量)和共同行为(行驶、刹车、鸣笛)。
  • “学生”是一个类:共同特征(姓名、年龄、学号),共同行为(上课、考试、交作业)。

类不对应具体的事物,而是一个“蓝图”——它定义了“有什么”(特征)和“能做什么”(行为),但不包含具体的数据。

2. 对象(Object):类的实例

对象是类的具体实例,是根据类模板创建的“具体事物”。例如:

  • 根据“汽车”类,可以创建出“我的黑色宝马轿车”“小明的白色特斯拉SUV”两个具体对象。
  • 根据“学生”类,可以创建出“张三(学号2024001)”“李四(学号2024002)”两个具体对象。

每个对象都拥有类定义的特征(属性)和行为(方法),且属性值各不相同(如宝马的品牌是“宝马”,特斯拉的品牌是“特斯拉”)。

3. 面向对象三大特性

  • 封装(Encapsulation):将对象的“属性”(数据)和“方法”(操作)封装在一起,对外隐藏内部实现细节,只通过指定接口(方法)交互,提高安全性。
  • 继承(Inheritance):子类可以继承父类的属性和方法,同时可以新增或重写方法,实现代码复用与扩展。
  • 多态(Polymorphism):不同类的对象对同一方法有不同的实现,调用时无需区分类型,直接使用统一接口,提高代码灵活性。

本文先聚焦“封装”(类与对象的核心),后续文章再详解继承与多态。

二、类的定义:设计“模板”的语法

在Python中,使用class关键字定义类,语法结构清晰,需遵循“类名首字母大写”的命名规范(如CarStudent),默认继承自object类(Python中所有类的基类)。

1. 类的基本语法

class 类名(父类名):"""类的文档字符串(描述类的功能)"""# 1. 类属性(可选):所有对象共享的属性(如汽车的“类型”都是“交通工具”)类属性名 = 属性值# 2. 初始化方法(__init__):创建对象时自动调用,用于初始化对象的属性def __init__(self, 参数1, 参数2, ...):# 实例属性:每个对象独有的属性,通过self绑定到实例self.实例属性名1 = 参数1self.实例属性名2 = 参数2# 3. 实例方法(必带self参数):描述对象的行为def 方法名1(self, 参数...):"""方法的文档字符串"""# 方法体:可访问self绑定的实例属性和其他方法代码逻辑# 4. 其他方法(如类方法、静态方法,后续详解)

关键组件解析:

  • __init__方法:称为“构造方法”或“初始化方法”,创建对象时自动执行,用于给对象初始化属性。它不是类的“构造函数”(Python中对象创建由__new__方法完成),但承担了初始化的核心职责。
  • self参数:所有实例方法的第一个参数必须是self,它代表当前对象的引用——通过self,方法可以访问对象的属性(如self.brand)和调用其他方法(如self.run())。调用方法时无需手动传递self,Python会自动绑定。
  • 类属性 vs 实例属性
    • 类属性:定义在__init__外,所有对象共享(如Car.type = "交通工具",所有汽车对象的type都是“交通工具”)。
    • 实例属性:定义在__init__内,通过self绑定,每个对象独有(如self.brand,宝马的brand是“宝马”,特斯拉的brand是“特斯拉”)。

2. 案例:定义Car

以“汽车”为例,定义包含“品牌、颜色”属性和“行驶”方法的Car类:

class Car(object):"""汽车类:描述汽车的品牌、颜色属性,以及行驶行为"""# 类属性:所有汽车共享的属性vehicle_type = "交通工具"  # 汽车属于“交通工具”类型def __init__(self, brand, color):"""初始化汽车对象的属性参数:brand: 汽车品牌(如“宝马”“特斯拉”)color: 汽车颜色(如“黑色”“白色”)"""# 实例属性:每个汽车对象独有的属性,通过self绑定self.brand = brandself.color = colordef run(self, speed):"""汽车行驶方法:打印行驶速度参数:speed: 行驶速度(如60、120,单位km/h)"""# 通过self访问实例属性(brand、color)print(f"一辆{self.color}{self.brand}汽车,以{speed}km/h的速度行驶中...")def honk(self):"""汽车鸣笛方法:打印鸣笛信息"""print(f"{self.brand}鸣笛:嘀嘀嘀~")

解析

  • 类属性vehicle_type:所有Car对象的vehicle_type都是“交通工具”,修改类属性会影响所有对象。
  • 实例属性self.brandself.color:每个Car对象的品牌和颜色不同,通过__init__的参数传入并初始化。
  • 实例方法run()honk():通过self访问实例属性,描述汽车的具体行为,调用时会输出个性化信息。

三、对象的创建与使用:从“模板”到“具体事物”

定义类后,通过“类名+括号”创建对象(实例化),再通过“对象名.属性”访问属性、“对象名.方法()”调用方法。

1. 创建对象(实例化)

创建对象的语法:对象名 = 类名(参数1, 参数2, ...)
参数需与__init__方法中除self外的参数对应(self由Python自动传递)。

# 创建第一个Car对象:黑色宝马
bmw_car = Car(brand="宝马", color="黑色")  # 传入brand和color参数,初始化实例属性# 创建第二个Car对象:白色特斯拉
tesla_car = Car("特斯拉", "白色")  # 也可省略参数名,按顺序传递

过程解析

  1. 执行Car("宝马", "黑色")时,Python先创建一个空的Car对象。
  2. 自动调用__init__方法,将空对象作为self传入,同时传递brand="宝马"color="黑色"
  3. __init__中,通过self.brand = "宝马"self.color = "黑色",给空对象绑定属性,完成初始化。
  4. 将初始化后的对象赋值给bmw_car变量,后续通过bmw_car操作该对象。

2. 访问属性(类属性与实例属性)

  • 访问实例属性:对象名.实例属性名(如bmw_car.brand)。
  • 访问类属性:对象名.类属性名类名.类属性名(推荐用类名访问,更清晰)。
# 访问实例属性
print(f"宝马汽车:品牌={bmw_car.brand},颜色={bmw_car.color}")  # 输出:宝马汽车:品牌=宝马,颜色=黑色
print(f"特斯拉汽车:品牌={tesla_car.brand},颜色={tesla_car.color}")  # 输出:特斯拉汽车:品牌=特斯拉,颜色=白色# 访问类属性(两种方式)
print(f"宝马的类型:{bmw_car.vehicle_type}")  # 输出:宝马的类型:交通工具(通过对象访问)
print(f"特斯拉的类型:{Car.vehicle_type}")     # 输出:特斯拉的类型:交通工具(通过类访问,推荐)# 修改实例属性(仅影响当前对象)
bmw_car.color = "灰色"  # 将宝马的颜色从“黑色”改为“灰色”
print(f"修改后宝马颜色:{bmw_car.color}")  # 输出:修改后宝马颜色:灰色
print(f"特斯拉颜色不变:{tesla_car.color}")  # 输出:特斯拉颜色不变:白色# 修改类属性(影响所有对象)
Car.vehicle_type = "机动车"
print(f"宝马的类型(修改后):{bmw_car.vehicle_type}")  # 输出:宝马的类型(修改后):机动车
print(f"特斯拉的类型(修改后):{tesla_car.vehicle_type}")  # 输出:特斯拉的类型(修改后):机动车

3. 调用方法

调用方法的语法:对象名.方法名(参数...)
参数需与方法中除self外的参数对应(self自动传递)。

# 调用run()方法:传入speed参数
bmw_car.run(speed=80)  # 输出:一辆灰色的宝马汽车,以80km/h的速度行驶中...
tesla_car.run(120)     # 输出:一辆白色的特斯拉汽车,以120km/h的速度行驶中...# 调用honk()方法:无额外参数
bmw_car.honk()  # 输出:宝马鸣笛:嘀嘀嘀~
tesla_car.honk()  # 输出:特斯拉鸣笛:嘀嘀嘀~

关键:方法中的self会自动绑定到调用方法的对象——调用bmw_car.run(80)时,self代表bmw_car,因此能访问self.brand(宝马)和self.color(灰色);调用tesla_car.run(120)时,self代表tesla_car,访问的是特斯拉的属性。

四、深入理解self:对象的“身份标识”

self是面向对象中最核心的概念之一,很多初学者会困惑“为什么必须写self”“self到底是什么”。简单来说,self当前对象的引用,它的核心作用是“绑定实例”——确保方法能找到当前对象的属性和其他方法。

1. self的本质:不是“关键字”,是“约定”

self不是Python的关键字,而是开发者之间的约定俗成——你可以将其改为this(如Java)、me等,但强烈不推荐(会降低代码可读性)。Python只要求“实例方法的第一个参数代表当前对象”,self是通用且易懂的选择。

# 不推荐:将self改为this(语法合法,但不符合约定)
class Test:def __init__(this, name):this.name = namedef say_hello(this):print(f"Hello, {this.name}")t = Test("Python")
t.say_hello()  # 输出:Hello, Python(语法正确,但不推荐)

2. self的核心作用:关联“方法”与“对象”

没有self,方法无法区分是哪个对象调用它——例如run()方法需要知道是“宝马”还是“特斯拉”在行驶,而self就是这个“关联桥梁”。

# 模拟无self的问题(伪代码,实际会报错)
class BadCar:def __init__(brand, color):  # 无self,无法绑定到对象brand = brand  # 变量仅在__init__内有效,对象无法访问color = colordef run(speed):  # 无self,无法访问brand和colorprint(f"一辆{color}{brand}汽车以{speed}km/h行驶")# 创建对象时,__init__的brand和color无法绑定到对象
bad_bmw = BadCar("宝马", "黑色")
# bad_bmw.run(80)  # 报错:name 'color' is not defined(无法找到color变量)

结论self是方法与对象的“纽带”——通过self,方法能精准访问当前对象的属性和调用其他方法,确保每个对象的行为都是“个性化”的。

五、对比:面向过程 vs 面向对象

为了更直观理解面向对象的优势,我们以“管理3辆汽车的信息并调用行驶方法”为例,对比两种编程范式的逻辑差异。

1. 面向过程实现:以“步骤”为核心

面向过程需要定义独立的函数,通过参数传递数据,代码会随着对象数量增加而变得冗长:

# 1. 定义存储汽车信息的列表(数据与操作分离)
cars = [{"brand": "宝马", "color": "黑色"},{"brand": "特斯拉", "color": "白色"},{"brand": "奥迪", "color": "银色"}
]# 2. 定义行驶函数(需手动传递汽车信息)
def car_run(car, speed):print(f"一辆{car['color']}{car['brand']}汽车以{speed}km/h行驶中...")# 3. 定义鸣笛函数
def car_honk(car):print(f"{car['brand']}鸣笛:嘀嘀嘀~")# 4. 遍历列表,调用函数(步骤繁琐)
for car in cars:car_run(car, 80)car_honk(car)print("-" * 20)

问题

  • 数据与操作分离:汽车信息(字典)和操作函数(car_run)是独立的,需要手动传递数据,易出错。
  • 扩展性差:若新增“刹车”功能,需新增car_brake函数;若汽车属性增加“排量”,需修改所有相关函数的参数。
  • 可读性低:随着对象和函数数量增加,代码会变成“函数堆”,难以维护。

2. 面向对象实现:以“对象”为核心

面向对象将数据(属性)和操作(方法)封装在类中,代码更简洁、易扩展:

# 1. 复用之前定义的Car类(数据与操作封装)
class Car(object):def __init__(self, brand, color):self.brand = brandself.color = colordef run(self, speed):print(f"一辆{self.color}{self.brand}汽车以{speed}km/h行驶中...")def honk(self):print(f"{self.brand}鸣笛:嘀嘀嘀~")# 2. 创建3个Car对象(直接通过类模板实例化)
cars = [Car("宝马", "黑色"),Car("特斯拉", "白色"),Car("奥迪", "银色")
]# 3. 遍历对象,调用方法(无需传递数据,直接调用)
for car in cars:car.run(80)car.honk()print("-" * 20)

优势

  • 封装性好:数据(brandcolor)和操作(runhonk)封装在Car类中,对象直接调用方法,无需手动传递数据。
  • 扩展性强:新增“刹车”功能,只需在Car类中新增brake()方法;新增“排量”属性,只需修改__init__,所有对象自动支持。
  • 可读性高:代码结构清晰,通过“对象.方法”的调用方式,直观反映“汽车在行驶”“汽车在鸣笛”的现实逻辑。

对比总结

维度面向过程面向对象
核心步骤(函数)对象(类+实例)
扩展性新增功能需修改大量函数新增功能只需扩展类,不影响其他代码
适用场景简单脚本、线性流程(如批处理)复杂项目、多实体交互(如游戏、管理系统)

六、实战案例:汽车管理系统(面向对象版)

为进一步展示面向对象的优势,我们实现一个简单的“汽车管理系统”,支持添加汽车、查看所有汽车信息、按品牌筛选汽车等功能。

class Car:"""汽车类:封装汽车的属性和行为"""def __init__(self, brand, color, price):self.brand = brand  # 品牌self.color = color  # 颜色self.price = price  # 价格(万元)def get_info(self):"""返回汽车的详细信息字符串"""return f"{self.color}{self.brand},价格:{self.price}万元"class CarManager:"""汽车管理类:负责汽车的添加、查询等管理功能"""def __init__(self):self.cars = []  # 存储所有汽车对象的列表def add_car(self, car):"""添加汽车到管理系统"""if isinstance(car, Car):  # 确保添加的是Car对象self.cars.append(car)print(f"添加成功:{car.get_info()}")else:print("添加失败:只能添加Car类型的对象")def show_all_cars(self):"""显示所有汽车的信息"""if not self.cars:print("系统中暂无汽车信息")returnprint("\n===== 所有汽车信息 =====")for i, car in enumerate(self.cars, 1):print(f"{i}. {car.get_info()}")print("=======================\n")def filter_by_brand(self, brand):"""按品牌筛选汽车"""filtered = [car for car in self.cars if car.brand == brand]if not filtered:print(f"未找到品牌为'{brand}'的汽车")returnprint(f"\n===== 品牌为'{brand}'的汽车 =====")for i, car in enumerate(filtered, 1):print(f"{i}. {car.get_info()}")print("=============================\n")# 测试汽车管理系统
if __name__ == "__main__":# 创建汽车管理对象manager = CarManager()# 添加汽车(创建Car对象并添加到管理系统)manager.add_car(Car("宝马", "黑色", 45.8))manager.add_car(Car("特斯拉", "白色", 32.5))manager.add_car(Car("宝马", "蓝色", 52.3))manager.add_car(Car("奥迪", "银色", 38.7))# 显示所有汽车manager.show_all_cars()# 按品牌筛选manager.filter_by_brand("宝马")manager.filter_by_brand("奔驰")

案例解析

  1. 类的职责划分

    • Car类:专注于封装汽车的属性(品牌、颜色、价格)和基础行为(get_info()返回信息),不关心“如何被管理”。
    • CarManager类:专注于汽车的管理逻辑(添加、展示、筛选),通过维护cars列表管理多个Car对象,不关心“汽车本身的属性细节”。
  2. 面向对象优势体现

    • 可扩展性:若需新增“汽车启动”功能,只需在Car类中添加start()方法;若需新增“按价格排序”功能,只需在CarManager中添加sort_by_price()方法,互不影响。
    • 可维护性:逻辑清晰,Car类和CarManager类各司其职,修改某类功能只需关注对应类,降低耦合度。
    • 复用性Car类可在其他需要“汽车”概念的场景中直接复用(如停车场系统、租车系统)。

七、常见问题与注意事项

  1. 类名与对象名的命名规范

    • 类名:采用“帕斯卡命名法”,首字母大写,如CarCarManager(清晰区分类与变量)。
    • 对象名:采用“蛇形命名法”,全小写,多个单词用下划线连接,如bmw_carcar_manager
  2. 实例属性必须通过self绑定
    未通过self绑定的变量只是__init__方法内的局部变量,对象无法访问:

    class WrongCar:def __init__(self, brand):brand = brand  # 错误:未绑定到self,对象无法访问car = WrongCar("宝马")
    # print(car.brand)  # 报错:'WrongCar' object has no attribute 'brand'
    
  3. 避免直接修改私有属性
    Python中,习惯在属性名前加下划线(_)表示“私有属性”(约定,非强制),应通过方法间接修改,确保数据安全:

    class SafeCar:def __init__(self, brand):self._brand = brand  # 约定为私有属性# 提供方法获取属性def get_brand(self):return self._brand# 提供方法修改属性(可添加校验逻辑)def set_brand(self, new_brand):if isinstance(new_brand, str) and new_brand.strip():self._brand = new_brandelse:print("品牌名称无效")
    
  4. __init__方法没有返回值
    __init__是初始化方法,负责给对象设置属性,不能有return语句(返回None也不行):

    class BadInit:def __init__(self, name):self.name = name# return name  # 错误:__init__不能有返回值
    

八、总结

面向对象编程是Python开发的核心思想,通过类与对象的封装,将现实世界的实体映射到代码中,使程序更贴近人类思维,更易扩展和维护。本文核心要点:

  1. 核心概念

    • 类是抽象模板(如“汽车”),对象是类的具体实例(如“我的宝马”)。
    • 封装、继承、多态是面向对象的三大特性,封装是基础(将属性和方法绑定到类中)。
  2. 类与对象的使用

    • class定义类,__init__方法初始化属性,实例方法描述行为(必带self)。
    • 通过对象名 = 类名(参数)创建对象,通过对象名.属性访问属性,对象名.方法()调用方法。
  3. self的作用
    代表当前对象的引用,是方法与对象之间的纽带,确保方法能访问对象的属性和其他方法。

  4. 面向对象的优势
    相比面向过程,代码更具封装性、扩展性和可读性,适合复杂项目开发。

掌握类与对象的基础后,后续可深入学习继承(代码复用)、多态(接口统一)、装饰器(增强方法功能)等高级特性,逐步构建完整的面向对象知识体系。

http://www.dtcms.com/a/403420.html

相关文章:

  • 阿里云电影网站建设教程2345浏览器网址导航
  • flutter json转实体类
  • MCU内存到下载的诸多问题
  • 论文解读:利用中断隔离技术的 Linux 亚微秒响应性能优化
  • 莱芜住房和城乡建设厅网站海外代理ip
  • 服务器时间同步校准
  • 本地应用程序如何通过 VPC Endpoint 或本地网络代理访问 AWS S3
  • 基于梯度下降、随机梯度下降和牛顿法的逻辑回归MATLAB实现
  • okhttp使用指南
  • 新余专业做淘宝网站2022年最新热点素材
  • 马鞍山网站建设制作中文网站怎么做英文版
  • GeoServer安装,并发布MapBox使用的矢量切片服务(pbf格式)(基于windows操作系统,使用shape文件发布)
  • 以AI科技重塑乳业生态,以京北品质服务健康中国 链农科技总经理马旭海专访
  • VMware安装 Rocky Linux 为后续docker k8s 实验做准备 自用 实践笔记(一)
  • Pyqt6开发的可以hexo博客一键创文章,发文章,统计文章。命令包装工具。
  • 链农科技亮相龙岗万达广场:“京北助力·舞动岭南”文艺展演
  • C语言(长期更新)第23讲:编译和链接
  • 怎么做网站后端手机登录凡科网
  • 如何自查家里宽带是否有公网IPv4?就几步。
  • Android studio导入OpenCV报“Unresolved reference: android“
  • 如何管理网站域名服务器做php网站
  • (Arxiv-2025)OmniInsert:无遮罩视频插入任意参考通过扩散 Transformer 模型
  • 大模型实战:通义万相2.1-文生视频-1.3B
  • 【C语言】统计二进制中1的个数:三种方法的比较与分析
  • C语言:数组元素逆序存放
  • C++(day1)
  • 如何让百度抓取网站wordpress 免费插件
  • 无人机无线电测距模块技术要点与难点
  • 逻辑回归中的成本损失函数全解析:从数学推导到实际应用
  • 组件化思维(下):表单与交互组件,倾听用户的心声