Day 16:【99天精通Python】面向对象编程(OOP)下篇 - 魔术方法与类属性

Day 16:【99天精通Python】面向对象编程(OOP)下篇 - 魔术方法与类属性

前言

欢迎来到第16天!

在之前的两天里,我们构建了 OOP 的大厦框架。今天,我们要进行内部装修,学习一些 Python 特有的"黑魔法"。

你是否好奇过:

  • 为什么print(obj)打印出来的是一串看不懂的地址,而别人的对象打印出来是清晰的信息?
  • 为什么 Python 的+号既能算数字加法,又能拼接字符串,甚至还能合并列表?
  • 所有的属性都必须绑定在self上吗?有没有属于类本身的属性?

本节内容:

  • 类属性 vs 实例属性
  • 实例方法、类方法、静态方法
  • 魔术方法 (Magic Methods) 详解
  • 运算符重载 (__add__,__eq__等)
  • 实战练习

一、类属性 vs 实例属性

1.1 概念区别

  • 实例属性:定义在__init__中,使用self.xxx每个对象独有一份,互不干扰。
  • 类属性:定义在类内部,方法之外。所有对象共享同一份

1.2 使用场景

classTool:# 类属性:所有工具共享的计数器count=0def__init__(self,name):# 实例属性:每个工具的名字不同self.name=name# 每创建一个对象,类属性 count 加 1Tool.count+=1t1=Tool("锤子")t2=Tool("扳手")print(f"工具1:{t1.name}")# 锤子print(f"工具2:{t2.name}")# 扳手print(f"当前工具总数:{Tool.count}")# 2

注意:访问类属性建议直接用类名.属性名(如Tool.count)。虽然t1.count也能访问,但容易引起混淆。


二、三种方法:各司其职

Python 的类中可以定义三种方法,它们通过装饰器来区分。

2.1 实例方法 (Instance Method)

  • 默认的方法。
  • 第一个参数是self(指向对象)。
  • 最常用,用于操作实例属性。

2.2 类方法 (Class Method)

  • 使用@classmethod装饰。
  • 第一个参数是cls(指向类本身,而不是对象)。
  • 常用于:工厂模式(不通过__init__创建对象) 或操作类属性。

2.3 静态方法 (Static Method)

  • 使用@staticmethod装饰。
  • 没有selfcls参数。
  • 它就像是一个普通函数,只是单纯地寄生在类里面,通常作为辅助工具

2.4 代码对比

classDateUtil:def__init__(self,year,month,day):self.year=year self.month=month self.day=day# 1. 实例方法:打印日期defshow(self):print(f"{self.year}-{self.month}-{self.day}")# 2. 类方法:通过字符串创建对象 (工厂模式)@classmethoddeffrom_string(cls,date_str):# date_str 格式 "2026-01-01"y,m,d=map(int,date_str.split("-"))returncls(y,m,d)# 相当于 DateUtil(y, m, d)# 3. 静态方法:验证日期是否有效 (不需要访问实例或类属性)@staticmethoddefis_valid(date_str):return"-"indate_str# 使用# 静态方法检查ifDateUtil.is_valid("2026-05-20"):# 类方法创建对象d=DateUtil.from_string("2026-05-20")# 实例方法显示d.show()# 2026-5-20

三、魔术方法 (Magic Methods)

在 Python 中,以双下划线开头和结尾的方法被称为魔术方法(也叫 Dunder Methods)。它们会在特定时机被自动调用

__init__就是最常见的魔术方法。

3.1 __str__ 与 __repr__:让对象"说人话"

当你print(obj)时,默认打印的是内存地址。实现__str__可以自定义打印内容。

classPerson:def__init__(self,name,age):self.name=name self.age=age# 面向用户:print() 时调用def__str__(self):returnf"Person(name='{self.name}', age={self.age})"# 面向开发者:命令行交互时调用 (通常用来排查问题)def__repr__(self):returnf"<Person{self.name}>"p=Person("Alice",25)print(p)# Person(name='Alice', age=25)

3.2 运算符重载:让对象支持 + - * /

为什么 Python 的字符串和列表可以相加?因为它们实现了__add__方法。我们也可以让自定义对象支持运算符。

示例:二维向量相加

classVector:def__init__(self,x,y):self.x=x self.y=ydef__str__(self):returnf"Vector({self.x},{self.y})"# 实现 + 号运算def__add__(self,other):# 返回一个新的 Vector 对象returnVector(self.x+other.x,self.y+other.y)# 实现 == 号比较def__eq__(self,other):returnself.x==other.xandself.y==other.y v1=Vector(2,4)v2=Vector(3,1)v3=v1+v2# 自动调用 v1.__add__(v2)print(v3)# Vector(5, 5)print(v1==v2)# Falseprint(v1==Vector(2,4))# True

3.3 其他常用魔术方法

  • __len__(self): 响应len(obj)
  • __call__(self): 让对象能像函数一样被调用obj()
  • __getitem__(self, key): 让对象支持索引访问obj[key]

四、实战练习

练习1:购物车 (支持 len 和打印)

定义Cart类,内部用列表存储商品。

  1. add(item): 添加商品。
  2. 实现__len__: 返回商品数量。
  3. 实现__str__: 打印所有商品名称。
classCart:def__init__(self):self.items=[]defadd(self,item):self.items.append(item)def__len__(self):returnlen(self.items)def__str__(self):returnf"购物车包含:{', '.join(self.items)}"my_cart=Cart()my_cart.add("苹果")my_cart.add("牛奶")print(len(my_cart))# 2print(my_cart)# 购物车包含: 苹果, 牛奶

练习2:分数类 (Fraction)

实现一个简单的分数类,支持分数的相加。
例如:1/2 + 1/4 = 3/4

classFraction:def__init__(self,top,bottom):self.top=top# 分子self.bottom=bottom# 分母def__str__(self):returnf"{self.top}/{self.bottom}"def__add__(self,other):# 通分公式: a/b + c/d = (ad + bc) / bdnew_top=self.top*other.bottom+other.top*self.bottom new_bottom=self.bottom*other.bottomreturnFraction(new_top,new_bottom)f1=Fraction(1,2)f2=Fraction(1,4)print(f1+f2)# 6/8 (暂时不涉及约分逻辑)

五、OOP 总结与回顾

到今天为止,OOP 的核心内容就讲完了。让我们回顾一下:

OOP 体系

类与对象

class 定义

obj 实例

self 关键字

三大特性

保护数据

复用代码

灵活调用

高级特性

类属性 vs 实例属性

@classmethod...

str,add...


六、常见问题

Q1:__init____new__有什么区别?

  • __new__是真正创建对象实例的方法(构造器)。
  • __init__是对象创建好后初始化属性的方法(初始化器)。
  • 99% 的情况我们只需要写__init__,除非你在做单例模式或继承不可变类型。

Q2:什么时候用@staticmethod

当你写了一个方法,发现它既不需要访问self(实例属性),也不需要访问cls(类属性),但逻辑上又跟这个类有关联时,就把它定义为静态方法。


七、小结

OOP 进阶

属性类型

方法类型

魔术方法

实例属性 (self.x) - 独享

类属性 (Class.x) - 共享

实例方法 (self)

类方法 @classmethod (cls)

静态方法 @staticmethod

str(打印)

add(运算)

len(长度)

关键要点

  1. 想要所有对象共享数据?用类属性
  2. 想要自定义print()的显示效果?写__str__
  3. 想要让对象支持+运算?写__add__
  4. 区分self(对象) 和cls(类) 的使用场景。

八、课后作业

  1. 计数器类:创建一个Person类,每实例化一个对象,类属性population加 1。实现一个__del__方法(析构函数,对象销毁时调用),让population减 1。
  2. 时间类运算:完善MyTime类,包含hour,minute。实现__add__方法,支持两个时间相加(注意进位,如 1:30 + 1:40 = 3:10)。
  3. 单例模式(挑战题):查阅资料,尝试用__new__方法实现一个单例类(无论创建多少次,都只返回同一个对象)。

下节预告

Day 17:异常处理 (Try-Except)- 程序报错了怎么办?直接崩溃吗?不!我们要学会优雅地处理错误,让程序坚不可摧。


系列导航

  • 上一篇:Day 15 - 面向对象编程(中)
  • 下一篇:Day 17 - 异常处理(待更新)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1146237.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

不同PWM频率下无源蜂鸣器声音效果对比分析

PWM频率如何“调教”无源蜂鸣器&#xff1f;一次听觉与物理的深度对话你有没有过这样的经历&#xff1a;在调试一个报警系统时&#xff0c;明明代码跑通了&#xff0c;蜂鸣器也“响”了&#xff0c;但声音却像是从老旧收音机里传出来的——低沉、模糊、甚至带点嗡嗡的震动感&am…

TI TPS系列在工业控制中的电源管理解决方案详解

工业控制电源设计的“隐形冠军”&#xff1a;TI TPS系列芯片实战解析在工业自动化现场&#xff0c;你可能见过这样的场景&#xff1a;一台PLC连续运行数年无故障&#xff0c;传感器节点在荒野中靠电池撑过三年未更换&#xff0c;高速数据采集系统在强电磁干扰下依然输出稳定信号…

OpenAMP RPMsg驱动架构全面讲解

OpenAMP RPMsg驱动架构深度解析&#xff1a;从原理到实战的完整指南在现代嵌入式系统中&#xff0c;“一个芯片跑多个操作系统”已不再是科幻场景。无论是智能音箱里的音频实时处理&#xff0c;还是工业PLC中的高精度电机控制&#xff0c;亦或是自动驾驶域控制器内的传感器融合…

Kafka从入门到入门

kafka的出现是为了支持大量消息事件&#xff0c;它的分布式设计、消息抽象设计及存储选择和优化性能手段都高效的支持了它的性能表现&#xff0c;同时面临分布式系统典型的信息同步、中心化设计、负载均衡等问题&#xff0c;对于这些问题kafka也给出了高效和多样化的选择&#…

手把手教程:使用Verilog实现简单组合逻辑电路

从零开始设计一个4:1多路选择器&#xff1a;深入理解Verilog组合逻辑建模你有没有遇到过这样的场景&#xff1f;多个信号源争抢同一个数据通路&#xff0c;而系统只能“听”一个。这时候&#xff0c;就需要一个数字世界的开关——多路选择器&#xff08;MUX&#xff09;&#x…

手把手教程:RISC-V指令集异常入口设置

手把手教你配置RISC-V异常入口&#xff1a;从原理到实战你有没有遇到过这样的情况&#xff1f;在调试一个裸机程序时&#xff0c;定时器中断就是不触发&#xff1b;或者一执行非法指令&#xff0c;CPU直接“跑飞”&#xff0c;连断点都抓不到&#xff1f;问题很可能出在——异常…

温度传感器热响应时间研究:封装材料对动态性能的影响

温度传感器热响应时间研究&#xff1a;封装材料如何“拖慢”或“加速”你的测温速度&#xff1f; 你有没有遇到过这种情况&#xff1a;电池包温度突然飙升&#xff0c;BMS却迟迟没报警&#xff1f;或者医疗设备加热管路已经开始冷凝&#xff0c;温度反馈还“慢半拍”&#xff1…

推荐Python、JavaScript或Scratch(儿童)。Python语法简洁,应用广泛;JavaScript适合

零基础学编程的核心步骤选择一门适合初学者的编程语言 推荐Python、JavaScript或Scratch&#xff08;儿童&#xff09;。Python语法简洁&#xff0c;应用广泛&#xff1b;JavaScript适合网页开发&#xff1b;Scratch通过图形化编程培养逻辑思维。理解编程基础概念 变量、数据类…

buck电路图及其原理:TPS5430补偿网络设计

深入理解Buck电路&#xff1a;从TPS5430看电流模式控制与补偿网络设计 你有没有遇到过这样的问题&#xff1f; 一个看起来“完全照着数据手册接”的电源电路&#xff0c;上电后输出电压却像心电图一样跳动不止——轻则纹波超标&#xff0c;重则直接振荡宕机。 如果你用的是像…

2026-01-12 全国各地响应最快的 BT Tracker 服务器(联通版)

数据来源&#xff1a;https://bt.me88.top 序号Tracker 服务器地域网络响应(毫秒)1http://211.97.119.76:2710/announce福建福州联通52http://123.245.62.83:6969/announce辽宁大连联通143http://60.249.37.20:6969/announce广东肇庆联通294http://211.75.205.189:80/announce…

掌握 requests、BeautifulSoup 等库的网络爬虫基础,或使用 pandas 进行简单数据分析

学习 Python 的基础语法从变量、数据类型、运算符等基础概念开始&#xff0c;逐步掌握条件语句、循环和函数。每天花 1-2 小时练习基础代码&#xff0c;确保理解核心语法规则。变量与数据类型&#xff1a;练习整数、浮点数、字符串和布尔值的操作控制结构&#xff1a;编写 if-e…

图解说明VHDL结构层次:顶层设计入门

从零构建数字系统&#xff1a;VHDL顶层设计的模块化思维实战你有没有遇到过这样的情况——写了一个几百行的VHDL代码&#xff0c;逻辑一改&#xff0c;整个功能就“炸”了&#xff1f;信号名混乱、端口连接错位、仿真结果莫名其妙……别急&#xff0c;这并不是你不够细心&#…

一文说清树莓派换源原理与常见问题解决方案

树莓派换源&#xff1a;不只是改个地址&#xff0c;更是理解 Linux 软件生态的第一课你有没有遇到过这样的场景&#xff1f;刚给树莓派通上电&#xff0c;满心欢喜地打开终端准备安装第一个软件——结果sudo apt update卡了十分钟&#xff0c;最后报出一串红字&#xff1a;Err:…

vivado2023.2下载安装超详细版:支持Win/Linux双平台

Vivado 2023.2 安装实战指南&#xff1a;从零搭建 FPGA 开发环境&#xff08;Windows Linux 双平台&#xff09; 你是不是也曾在深夜对着“Failed to extract files”这种错误提示束手无策&#xff1f; 是不是下载了几十GB的安装包&#xff0c;结果卡在85%整整一小时&#x…

安全继电器模块PCB原理图设计新手教程

从零开始设计一个安全继电器模块&#xff1a;原理图实战入门指南你有没有遇到过这样的情况&#xff1f;在做一个自动化控制项目时&#xff0c;明明程序写得没问题&#xff0c;继电器也“咔哒”响了&#xff0c;结果设备却在不该运行的时候突然启动——或者更糟&#xff0c;紧急…

科技是把双刃剑ai到底是不是双刃剑

科技双刃剑属性概述定义科技双刃剑的核心特征&#xff08;利弊并存&#xff09;历史案例&#xff08;如核能、互联网的正面与负面影响&#xff09;引出AI作为典型双刃剑技术的争议性AI的积极应用场景效率提升&#xff1a;自动化生产、数据分析加速决策医疗突破&#xff1a;疾病…

vivado除法器ip核与自定义逻辑对比:核心要点解析

FPGA除法运算的两条路&#xff1a;IP核与手搓逻辑&#xff0c;谁更适合你的项目&#xff1f; 在FPGA开发中&#xff0c;加法、乘法早已习以为常&#xff0c;但一碰到 除法 &#xff0c;不少工程师还是会心头一紧。不像ASIC可以依赖强大的算术单元&#xff0c;FPGA上的除法没…

RabbitMQ 消息消费模式深度解析

本文深入探讨 RabbitMQ 中 Exchange、Queue、Routing Key 的协作机制&#xff0c;以及不同场景下的消息消费策略。一、核心概念回顾RabbitMQ 消息流转的核心链路&#xff1a;1.1 Exchange 类型类型特点使用场景direct精确匹配 routing key点对点消息&#xff0c;精确路由topic通…

基于Web的模拟混频电路在线仿真操作指南

用浏览器就能玩转射频电路&#xff1a;在线仿真混频器的实战教学 你有没有过这样的经历&#xff1f;想验证一个简单的模拟混频电路&#xff0c;却要花半天时间安装LTspice、配置模型路径、翻找元件库&#xff1b;或者在课堂上讲调幅信号生成时&#xff0c;学生一脸茫然&#x…

SiFive平台移植RISC-V裸机程序从零实现指南

从零开始在 SiFive 平台运行 RISC-V 裸机程序&#xff1a;不只是“点灯”&#xff0c;而是真正理解底层启动机制你有没有试过&#xff0c;在一块全新的开发板上连一个 LED 都点不亮&#xff1f;不是代码写错了&#xff0c;也不是接线问题——而是程序根本没跑起来。这种情况在裸…