【Python全栈开发】第4讲 | 面向对象进阶:从“封装继承”到“设计模式”的蜕变

1. 灵魂拷问:为什么我们要搞 OOP?

兄弟们,如果你还在写那种"一个脚本从头拉到尾"的代码,那这一讲你得坐稳了。

面向对象编程(Object-Oriented Programming, OOP)不是为了把简单的事情搞复杂,而是为了在大规模协作时,代码不至于变成一团乱麻

  • 过程式编程:像是在写一份详细的"炒菜步骤"。
  • 面向对象编程:像是在雇佣一个"专业厨师"。你不需要知道他怎么切菜、怎么控温,你只需要告诉他:“厨师,给我来份宫保鸡丁!”

今天,咱们就来聊聊怎么从一个"写步骤的"变成一个"雇人的"。


2. 基础:类(Class)与对象(Object)

2.1 模具与成品

  • 类 (Class):就是一张"图纸"或者一个"模具"。它定义了东西长啥样,能干啥。
  • 对象 (Object):就是根据图纸造出来的"实物"。
classRobot:def__init__(self, name, version):# self 就是对象自己,像是每个人的身份证 self.name = name self.version = version defsay_hello(self):print(f"你好!我是机器人 {self.name},版本号:{self.version}")# 造两个机器人 r1 = Robot("小爱","v1.0") r2 = Robot("小度","v2.0") r1.say_hello() r2.say_hello()

2.2 别再问 self 是干啥的了

self 就像是函数里的一个占位符。当你喊 r1.say_hello() 时,Python 自动把 r1 这个实例传给了 self。这样函数才知道该打印"小爱"还是"小度"。

2.3 类与对象的内存布局

理解内存布局是掌握面向对象的关键。让我们看看 Python 中类和对象是如何在内存中存储的:

classPerson: species ="Homo sapiens"# 类属性(存在类对象中)def__init__(self, name, age): self.name = name # 实例属性(存在实例对象中) self.age = age defgreet(self):# 实例方法returnf"Hello, I'm {self.name}"# 内存布局分析 p1 = Person("Alice",25) p2 = Person("Bob",30)# 类属性是所有实例共享的print(Person.species)# Homo sapiensprint(p1.species)# Homo sapiens(通过实例访问类属性)print(p2.species)# Homo sapiens# 修改类属性会影响所有实例 Person.species ="Human"print(p1.species)# Human# 但给实例赋值会创建实例属性,不影响其他实例 p1.species ="Modified"print(p1.species)# Modified(实例属性遮蔽类属性)print(p2.species)# Human(仍然访问类属性)print(Person.species)# Human

内存布局要点

  • 类对象:存储类属性、方法定义,只有一份
  • 实例对象:存储实例属性,每个实例独立一份
  • 方法查找:实例方法实际存储在类中,实例通过 __class__ 引用找到方法

3. 三大特性:封装、继承、多态

3.1 封装 (Encapsulation):把脏活累活藏起来

你不希望别人随便改你的内部数据。在 Python 里,用双下划线 __ 就能把变量藏起来。

classBankAccount:def__init__(self, balance): self.__balance = balance # 私有变量,外面看不到defdeposit(self, amount):if amount >0: self.__balance += amount print(f"存入成功,当前余额:{self.__balance}")defget_balance(self):return self.__balance account = BankAccount(1000)# print(account.__balance) # 这行会报错!print(account.get_balance())# 只能通过我给你的接口来查

3.2 继承 (Inheritance):少写代码的捷径

如果你要写"猫"和"狗",它们都有"吃"和"睡"的功能,那就先写个"动物"类。

classAnimal:defeat(self):print("正在吃东西...")classDog(Animal):# 狗继承了动物defbark(self):print("汪汪汪!") my_dog = Dog() my_dog.eat()# 继承来的 my_dog.bark()# 自己有的

3.3 多态 (Polymorphism):鸭子类型

Python 的多态特别佛系。只要你长得像鸭子,叫起来也像鸭子,那我就把你当鸭子。


4. 深入:MRO(方法解析顺序)算法详解

当类存在多重继承时,Python 如何决定调用哪个方法?这就是 MRO(Method Resolution Order)要解决的问题。

4.1 什么是 MRO

MRO 定义了 Python 查找方法和属性的顺序。Python 3 使用 C3 线性化算法 来计算 MRO。

classA:defmethod(self):print("A.method")classB(A):defmethod(self):print("B.method")classC(A):defmethod(self):print("C.method")classD(B, C):# 多重继承pass# 查看 MROprint(D.__mro__)# 输出:(<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)

4.2 C3 线性化算法的核心规则

  1. 子类优先于父类:先查找子类,再查找父类
  2. 单调性:如果 C 是 D 的父类,那么在 C 的 MRO 中出现的类,在 D 的 MRO 中也以相同顺序出现
  3. 从左到右:按照继承列表中的顺序查找
# 复杂继承示例classBase:defgreet(self):print("Base greet")classMixin1(Base):defgreet(self):print("Mixin1 greet")super().greet()classMixin2(Base):defgreet(self):print("Mixin2 greet")super().greet()classCombined(Mixin1, Mixin2):defgreet(self):print("Combined greet")super().greet()# MRO: Combined -> Mixin1 -> Mixin2 -> Base -> object c = Combined() c.greet()# 输出:# Combined greet# Mixin1 greet# Mixin2 greet# Base greet

4.3 使用 super() 的正确姿势

super() 不是调用父类,而是按照 MRO 顺序调用下一个类。

classA:def__init__(self):print("A.__init__")super().__init__()classB(A):def__init__(self):print("B.__init__")super().__init__()classC(A):def__init__(self):print("C.__init__")super().__init__()classD(B, C):def__init__(self):print("D.__init__")super().__init__() d = D()# 输出顺序:D -> B -> C -> A# 注意:A 的 super() 调用 object.__init__(),什么都不做

5. 进阶:描述符(Descriptor)机制

描述符是 Python 中实现属性访问控制的核心机制。理解描述符,你就理解了 @property@staticmethod@classmethod 的本质。

5.1 什么是描述符

描述符协议:实现了 __get____set____delete__ 方法的类就是描述符。

classValidator:"""一个描述符,用于验证属性值"""def__init__(self, min_value, max_value): self.min_value = min_value self.max_value = max_value self.name =Nonedef__set_name__(self, owner, name):"""当描述符被赋值给类属性时调用""" self.name = name self.storage_name =f"_{name}"def__get__(self, instance, owner):"""获取属性值时调用"""if instance isNone:return self returngetattr(instance, self.storage_name,None)def__set__(self, instance, value):"""设置属性值时调用"""ifnotisinstance(value,(int,float)):raise TypeError(f"{self.name} must be a number")ifnot self.min_value <= value <= self.max_value:raise ValueError(f"{self.name} must be between {self.min_value} and {self.max_value}")setattr(instance, self.storage_name, value)classPerson: age = Validator(0,150)# age 是一个描述符实例 salary = Validator(0,1000000)def__init__(self, name, age, salary): self.name = name self.age = age # 触发描述符的 __set__ self.salary = salary # 使用 p = Person("Alice",25,50000)print(p.age)# 25# p.age = 200 # ValueError: age must be between 0 and 150# p.salary = "high" # TypeError: salary must be a number

5.2 描述符的类型

类型实现的方法说明
非数据描述符只有 __get__实例属性优先于描述符
数据描述符__set____delete__描述符优先于实例属性
classNonDataDescriptor:"""非数据描述符"""def__get__(self, instance, owner):return"from descriptor"classDataDescriptor:"""数据描述符"""def__get__(self, instance, owner):return"from descriptor"def__set__(self, instance, value):print("Setting value")classTestNonData: attr = NonDataDescriptor()classTestData: attr = DataDescriptor()# 非数据描述符:实例属性优先 t1 = TestNonData() t1.attr ="from instance"print(t1.attr)# from instance# 数据描述符:描述符优先 t2 = TestData() t2.attr ="from instance"# 触发 __set__print(t2.attr)# from descriptor(__get__ 仍然被调用)

5.3 property 的本质

@property 其实就是用描述符实现的:

# property 的简化版实现classProperty:def__init__(self, fget=None, fset=None, fdel=None): self.fget = fget self.fset = fset self.fdel = fdel def__get__(self, instance, owner):if instance isNone:return self if self.fget isNone:raise AttributeError("can't get attribute")return self.fget(instance)def__set__(self, instance, value):if self.fset isNone:raise AttributeError("can't set attribute") self.fset(instance, value)defsetter(self, fset): self.fset = fset return self # 使用自定义 PropertyclassCircle:def__init__(self, radius): self._radius = radius @Propertydefradius(self):return self._radius @radius.setterdefradius(self, value):if value <0:raise ValueError("Radius cannot be negative") self._radius = value 

6. 进阶:属性查找机制

理解 Python 如何查找属性,是掌握面向对象编程的关键。

6.1 属性查找顺序

对于 obj.attr,Python 按以下顺序查找:

  1. 数据描述符:在 obj.__class__ 中查找 attr,如果是数据描述符,返回描述符的值
  2. 实例字典:在 obj.__dict__ 中查找 attr
  3. 非数据描述符:在 obj.__class__ 及其父类的 __dict__ 中查找 attr
  4. 类属性:在 obj.__class__ 及其父类的 __dict__ 中查找 attr
  5. __getattr__:如果以上都没找到,调用 __getattr__
classDescriptor:"""数据描述符"""def__get__(self, instance, owner):return"descriptor value"def__set__(self, instance, value):passclassMyClass: attr = Descriptor()def__init__(self): self.__dict__['attr']="instance value"def__getattr__(self, name):returnf"{name} not found, using getattr" obj = MyClass()print(obj.attr)# descriptor value(数据描述符优先于实例属性)# 如果描述符没有 __set__classNonDataDescriptor:def__get__(self, instance, owner):return"descriptor value"classMyClass2: attr = NonDataDescriptor()def__init__(self): self.attr ="instance value" obj2 = MyClass2()print(obj2.attr)# instance value(实例属性优先于非数据描述符)

6.2 自定义属性访问

classAttributeTracer:"""追踪所有属性访问"""def__init__(self): self._data ={}def__getattribute__(self, name):"""拦截所有属性访问"""if name.startswith('_'):returnobject.__getattribute__(self, name)print(f"Getting: {name}")returnobject.__getattribute__(self,'_data').get(name)def__setattr__(self, name, value):"""拦截所有属性设置"""if name.startswith('_'):object.__setattr__(self, name, value)else:print(f"Setting: {name} = {value}")object.__getattribute__(self,'_data')[name]= value def__getattr__(self, name):"""属性不存在时调用"""print(f"Attribute {name} not found")returnNone obj = AttributeTracer() obj.x =10# Setting: x = 10print(obj.x)# Getting: x -> 10print(obj.y)# Getting: y -> Attribute y not found -> None

7. 进阶:元类(Metaclass)入门

元类是"类的类",它控制类的创建过程。理解元类,你就站在了 Python 面向对象编程的顶端。

7.1 什么是元类

在 Python 中,一切皆对象。类也是对象,而创建类的"东西"就是元类。默认情况下,所有类都是由 type 创建的。

classMyClass:pass# MyClass 是 type 的实例print(type(MyClass))# <class 'type'># 等价于 MyClass2 =type('MyClass2',(),{})print(type(MyClass2))# <class 'type'>

7.2 自定义元类

通过继承 type,我们可以控制类的创建过程:

classSingletonMeta(type):"""单例模式元类""" _instances ={}def__call__(cls,*args,**kwargs):"""控制实例创建"""if cls notin cls._instances: cls._instances[cls]=super().__call__(*args,**kwargs)return cls._instances[cls]classDatabase(metaclass=SingletonMeta):"""使用元类实现单例"""def__init__(self, connection_string): self.connection_string = connection_string print(f"Initializing database with {connection_string}") db1 = Database("postgresql://localhost/db") db2 = Database("mysql://localhost/db")print(db1 is db2)# True(同一个实例)print(db1.connection_string)# postgresql://localhost/db

7.3 元类的 newinit

classAutoRegisterMeta(type):"""自动注册子类的元类""" registry ={}def__new__(mcs, name, bases, namespace):"""创建类对象时调用"""print(f"Creating class: {name}")# 可以修改类的属性和方法 namespace['created_by']='AutoRegisterMeta' cls =super().__new__(mcs, name, bases, namespace)# 注册类(排除元类本身)if name !='BaseModel': mcs.registry[name]= cls return cls def__init__(cls, name, bases, namespace):"""初始化类对象时调用"""print(f"Initializing class: {name}")super().__init__(name, bases, namespace)classBaseModel(metaclass=AutoRegisterMeta):"""所有模型的基类"""passclassUser(BaseModel):passclassProduct(BaseModel):passprint(AutoRegisterMeta.registry)# {'User': <class '__main__.User'>, 'Product': <class '__main__.Product'>}

7.4 元类的实际应用

classORMMeta(type):"""简化 ORM 模型定义的元类"""def__new__(mcs, name, bases, namespace):# 收集所有字段定义 fields ={}for key, value inlist(namespace.items()):ifisinstance(value, Field): fields[key]= value value.name = key namespace['_fields']= fields returnsuper().__new__(mcs, name, bases, namespace)classField:"""字段定义"""def__init__(self, field_type, nullable=True): self.field_type = field_type self.nullable = nullable self.name =Nonedef__repr__(self):returnf"Field({self.field_type})"classModel(metaclass=ORMMeta):"""ORM 基类"""def__init__(self,**kwargs):for name, field in self._fields.items(): value = kwargs.get(name)if value isNoneandnot field.nullable:raise ValueError(f"{name} is required")setattr(self, name, value)defsave(self):"""模拟保存到数据库""" data ={name:getattr(self, name)for name in self._fields}print(f"Saving {self.__class__.__name__}: {data}")classUser(Model):id= Field(int, nullable=False) name = Field(str, nullable=False) email = Field(str)# 使用 user = User(id=1, name="Alice", email="[email protected]") user.save()# Saving User: {'id': 1, 'name': 'Alice', 'email': '[email protected]'}

8. 魔法方法:让你的类更"Pythonic"

Python 里有很多双下划线开头结尾的方法(Dunder Methods),它们能让你的对象支持 +, -, len() 等操作。

classBook:def__init__(self, title, pages): self.title = title self.pages = pages def__str__(self):# 当你 print(book) 时,会调用这个returnf"《{self.title}》- 共{self.pages}页"def__len__(self):# 当你 len(book) 时,会调用这个return self.pages def__eq__(self, other):# 比较两个 Book 对象ifnotisinstance(other, Book):returnFalsereturn self.title == other.title and self.pages == other.pages def__add__(self, other):# 实现 Book + Bookifisinstance(other, Book):return Book(f"{self.title} + {other.title}", self.pages + other.pages)return NotImplemented my_book = Book("Python 从入门到放弃",999)print(my_book)print(f"这本书厚度:{len(my_book)}") book2 = Book("Python 从入门到放弃",999)print(my_book == book2)# True combined = my_book + book2 print(combined)# 《Python 从入门到放弃 + Python 从入门到放弃》- 共1998页

9. 综合实战:简易 RPG 战斗系统

咱们来个硬核的,用 OOP 写个简单的游戏角色对战逻辑。

import random classCharacter:def__init__(self, name, hp, ad): self.name = name self.hp = hp self.ad = ad # 攻击力defis_alive(self):return self.hp >0defattack(self, target): damage = self.ad + random.randint(-5,5)print(f"【{self.name}】发起攻击,对【{target.name}】造成了 {damage} 点伤害!") target.receive_damage(damage)defreceive_damage(self, damage): self.hp -= damage if self.hp <0: self.hp =0print(f"【{self.name}】剩余血量:{self.hp}")classWarrior(Character):def__init__(self, name):super().__init__(name, hp=150, ad=20)# 战士血厚defreceive_damage(self, damage):# 战士有 20% 几率格挡if random.random()<0.2:print(f"【{self.name}】格挡了攻击!") damage = damage //2super().receive_damage(damage)classMage(Character):def__init__(self, name):super().__init__(name, hp=80, ad=45)# 法师攻高defattack(self, target):# 法师有 30% 几率暴击if random.random()<0.3: damage =int(self.ad *1.5)+ random.randint(-5,5)print(f"【{self.name}】发动暴击!")else: damage = self.ad + random.randint(-5,5)print(f"【{self.name}】发起攻击,对【{target.name}】造成了 {damage} 点伤害!") target.receive_damage(damage)# 开始战斗 p1 = Warrior("盖伦") p2 = Mage("拉克丝")print("--- 战斗开始 ---")while p1.is_alive()and p2.is_alive(): p1.attack(p2)ifnot p2.is_alive():print(f"\n恭喜【{p1.name}】获得胜利!")break p2.attack(p1)ifnot p1.is_alive():print(f"\n恭喜【{p2.name}】获得胜利!")break

10. 避坑小贴士(老司机的叮嘱)

  1. 别为了 OOP 而 OOP:如果一个功能写个函数就能搞定,千万别强行封装个类。过度设计是万恶之源。
  2. 优先使用组合而非继承:如果你发现继承树超过 3 层,说明你的架构出问题了。记住:“Has-a” 往往比 “Is-a” 更灵活
  3. self 别漏写:在类的方法里访问属性,必须带 self.,这是新手最容易犯的低级错误。
  4. 理解 MRO 再使用多重继承:多重继承很强大,但如果不理解 MRO,很容易踩坑。
  5. 慎用元类:元类是强大的工具,但会增加代码复杂度,只在必要时使用。

11. 实战演练:巩固你的内功

OOP 是设计出来的,不是写出来的。动动手,感受一下"上帝视角"。

Read more

【AI应用开发工程师】-分享Java 转 AI成功经验

【AI应用开发工程师】-分享Java 转 AI成功经验

Java 转 AI:别再死磕书本了,老司机带你飞! 文章目录 * Java 转 AI:别再死磕书本了,老司机带你飞! * ⭐AI 大模型应用开发全方位成长路线⭐ * 一、Java 老兵的 AI 转型焦虑:书本,你真的跟不上时代了! * 二、AI 导师,你的专属学习外挂! * 三、抱紧大腿,和 AI 大佬一起成长! * 四、拓展方案一:开源社区,你的 AI 练兵场! * 五、拓展方案二:小步快跑,项目实战是王道! * 六、拓展方案三:知识管理,告别“学了就忘”的魔咒! * 七、总结:转型 AI,一场充满乐趣的冒险!

By Ne0inhk

2026年03月17日全球AI前沿动态

一句话总结:2026年3月16日的AI行业资讯覆盖315曝光GEO技术操纵AI的行业乱象、多款大模型与智能体技术的重磅迭代、AI在多行业的深度落地、头部企业的布局与资本动作,同时AI安全治理、职业替代风险、伦理争议等问题引发广泛关注,政策层面将AI定为支柱产业并重点培育具身智能等前沿领域,技术发展与行业治理的协同成为行业核心议题。 一、模型与技术突破 1.1 通用大模型(大语言模型与多模态模型) 1. Anthropic:发布Claude Opus 4.6和Sonnet 4.6,100万上下文全面开放,取消长文本溢价,Opus每百万Token计费5美元和25美元;多模态处理能力提升6倍,单次请求支持图像/PDF页面上限从100增至600,API长请求无需Beta请求头自动处理;MRCR v2评测中Opus 4.6以78.3%位列同级模型第一,Claude Code用户默认开启百万上下文,大幅减少强制压缩次数;推出限时福利,3月13日-27日工作日非高峰时段用户用量翻倍,覆盖多平台,推动百万Token时代到来,突破AI编程与长文本处理上限。 2. 智谱:发布GLM-5-Tur

By Ne0inhk
为什么要学习人工智能(AI)?—— 未来已来,AI引领时代变革

为什么要学习人工智能(AI)?—— 未来已来,AI引领时代变革

未来已来,AI引领时代变革 在这个日新月异的时代,人工智能(AI)正以不可阻挡之势重塑着我们的世界。从教育的深耕细作到科研的突破创新,从行政的效率提升到管理的智慧化转型,AI技术如同一股强大的潮流,渗透到了各行各业的每一个角落。如果你还在对是否学习AI犹豫不决,那么不妨跟随我的笔触,一起探索AI在教育、科研、行政这三大关键领域的深刻变革,或许你会发现,掌握AI不仅是顺应时代的必然选择,更是推动职业发展的强大引擎。 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,可以分享一下给大家。点击跳转到网站。 https://www.captainbed.cn/ccc 文章目录 * 未来已来,AI引领时代变革 * 一、AI赋能教育:教学方式的革命性转变 * 二、AI重塑行政:管理模式的智慧化升级 * 技术实现详解: * 决策支持系统 * 数字人服务架构 * 三、AI驱动科研:科研范式的全面革新 * 四、深入学习AI:时代的召唤与个人的选择 * 五、结语:未来已来,AI与你同行

By Ne0inhk
【GitHub周榜】WrenAI:开源SQL AI代理,让Text-to-SQL轻松实现,开启自然语言与数据交互新时代

【GitHub周榜】WrenAI:开源SQL AI代理,让Text-to-SQL轻松实现,开启自然语言与数据交互新时代

系列篇章💥 No.文章1【GitHub周榜】OpenHands:AI赋能,软件开发效率狂飙10倍2【GitHub周榜】Agno:快速构建多模态智能体的轻量级框架,开发提速 10000 倍3【GitHub周榜】WrenAI:开源SQL AI代理,让Text-to-SQL轻松实现,开启自然语言与数据交互新时代 目录 * 系列篇章💥 * 前言 * 一、项目概述 * 二、主要功能 * 1、多语言自然对话 * 2、智能数据探索 * 3、语义索引系统 * 4、上下文 SQL 生成 * 5、无代码数据分析 * 6、AI 驱动可视化 * 7、数据导出集成 * 8、安全性保障 * 三、技术原理 * 四、应用场景 * 1、

By Ne0inhk