用游戏角色系统实战Python面向对象:class、继承、多态一次搞懂
很多人学Python学到面向对象这一章就卡壳了class、self、__init__、继承、多态这些概念单独看都能看懂合在一起就不知道它们到底在解决什么问题。平时写的脚本从上往下跑变量和函数一多完全没头绪一到真正的项目里就掉头发。我的建议很简单别死啃语法直接拿一个小游戏角色系统练手。角色、技能、血量、组队、打怪这些游戏里的天然概念和面向对象编程OOP的套路几乎是完美对应的。把这个系统写出来你会突然发现class不是考试名词而是帮你管理复杂代码的工具。这篇文章就带你从零搭一套带英雄、怪物、回合制战斗的角色系统代码可直接运行能动手跑一遍的项目比看十遍教程管用。1. 为什么要用游戏角色系统讲Python面向对象1.1 函数式写法的痛苦数据与逻辑在打架先回忆一下没有class的时候我们怎么描述一个角色。最常见的做法是拿字典装属性hero {名字: 阿伟, 血量: 100, 攻击: 20, 防御: 5} monster {名字: 史莱姆, 血量: 50, 攻击: 10, 防御: 2}然后写一堆函数去操作这些字典def attack(attacker, target): damage attacker[攻击] - target[防御] target[血量] - damage return damage这个写法在只有一个英雄、一个怪物时挺清楚。可一旦角色多了比如队伍里有五个角色、敌人也有五种每个角色还得带技能、经验值、升级、装备你会发现每个函数都要小心翼翼地记住字典里有哪些键改错一个键名就全线崩盘。要加一个“施法消耗魔法”的功能你得在十几个函数里同步修改逻辑。“谁这个怪物”完全靠字典的数字状态去推断代码根本没法表达“这个角色还活着么”“能不能用技能”这层业务含义。最难受的是数据和操作数据的方法是分离的两堆代码一旦规模大一点人脑根本记不住它们之间的关联。游戏里那么多个对象每个对象有自己的状态、自己的行为用函数一路平铺下去写出来的东西就是一堆纠缠在一起的线头。1.2 面向对象的核心思路把数据和行为捆成整体面向对象编程做了一件看起来非常朴素的事把某个概念的数据血量、攻击、等级和行为攻击、被攻击、升级放在一起封装成一个“对象”。你不需要记住“哪个字典是哪个角色的”你拿到一个英雄实例它自己就知道自己叫啥、有多少血、会什么招式。想让它打人直接调用它的方法就行想让怪物打它直接调用怪物的方法。至于内部状态如何变化那由对象自己负责外部代码不用管也没法随手乱改。用一个生活化的类比来感受一下一辆汽车是一个对象油表、车速是它的属性踩油门、刹车是它的方法。你驾驶汽车时不用自己拧开油箱盖手动算速度你只需要踩踏板车自己根据燃油量决定输出多少动力。把油门逻辑藏进车身里对外统一呈现出“踩油门就提速”的接口这就是“封装”的直观感受。当我们讨论完这个概念之后需要承认一个事实游戏本身就是由一大堆对象构成的角色是对象、怪物是对象、道具是对象、技能是对象。拿游戏场景讲解面向对象基本上就是在用母语教学。2. 先把这几个容易绕晕的概念给破了2.1 类、实例、self到底是谁很多初学者卡在这里核心是没理解self为什么不请自来。先定义一下class是画图纸实例是根据图纸造出来的那辆车。图纸可以反复使用同一个类可以造无数个实例。每个实例的数据是独立的但方法代码是共享的——你不可能给每辆车都重新造一套发动机图纸吧那么问题来了方法代码是共享的attack(self, target)这个方法在调用hero.attack(monster)的时候Python怎么知道该攻击谁、谁受到了攻击答案就是self。调用hero.attack(monster)时Python会偷偷在参数列表最前面塞一个hero对象的引用变成attack(hero, monster)。所有写在方法里的self.xxx其实都是在说“当前这个实例的xxx”。self不是语法糖它是对象方法里那个“被操作对象本身”的占位符。很多新手在方法里忘了写self.去直接操作一个局部变量结果就是报错或者改错数据原因就在这里。2.2 __init__不是构造函数要叫它初始化器网上很多教程说__init__是构造函数这个说法其实不准确。Python里真正负责创建实例的是__new____init__只负责在对象创建之后填充初始状态相当于房子已经砌好了你进去摆家具、刷墙。至于为什么方法名前后要双下划线这是Python的约定写法表示“魔法方法”Python解释器在特定场景会自己调用它们。__init__就是那个场景——当你写Warrior(阿伟, 120, 18, 8)时Python自动分配好一个空壳对象然后调用它的__init__方法把参数传进去。2.3str让对象说人话先做个小实验定义好一个类之后直接打印实例print(hero)你多半会看到一行__main__.Warrior object at 0x000001F0A2C1A5D0这其实是一个对象的默认身份信息类名加它在内存里的地址。这么看很不直观。你更希望打印英雄时直接看到“阿伟HP 120/120攻击 18”这样的描述。这时就需要重写__str__方法def __str__(self): return f{self.name}HP {self.hp}/{self.max_hp}攻击 {self.atk}print一个对象的时候Python会自动调用它的__str__方法来决定要打印什么内容。这是一个低成本、高收益的习惯把对象以人类可读的方式展示出来你能省掉大量调试时间——黑盒调试永远不如直接看输出直观。3. 动手搭建一套可运行的游戏角色系统3.1 先造一个万能角色基类Character我建议先从基类入手。所谓基类就是“所有角色都有的共性”。无论战士还是法师它们都有名字、血量、攻击力、防御力都会被攻击、会打别人、会升级这些共同点集中写在一个Character类里。import time class Character: # 类属性所有角色共享可以直接通过 类名.属性名 访问 GAME_NAME Python小小世界 def __init__(self, name, hp, atk, defense): self.name name # 实例属性 self.max_hp hp self.hp hp self.atk atk self.defense defense self.level 1 self.exp 0 def is_alive(self): 判断角色是否存活 return self.hp 0 def take_damage(self, damage): 承伤逻辑防御结算至少扣1点血 actual max(1, damage - self.defense) self.hp max(0, self.hp - actual) return actual def attack(self, target): 普通攻击 if self.is_alive() and target.is_alive(): actual target.take_damage(self.atk) print(f{self.name} 攻击 {target.name}造成 {actual} 点伤害) return actual return 0 def gain_exp(self, amount): 获得经验并判断升级 self.exp amount need self.level * 100 if self.exp need: self.exp - need self.level 1 self.max_hp 10 self.hp self.max_hp self.atk 2 self.defense 1 print(f【{self.name} 升级了】当前等级 {self.level}属性已提升) def __str__(self): return f{self.name} [Lv.{self.level}] HP {self.hp}/{self.max_hp} 攻 {self.atk} 防 {self.defense}这里有几个值得说透的细节self.max_hp和self.hp都从同一个构造参数复制出来目的是让“血量上限”和“当前血量”成为两个独立的量。战斗中只会改当前血量恢复满血时知道回到哪个上限。take_damage中用了max(1, damage - self.defense)一方面是防御结算另一方面强制最少扣1点血。不这么做的话可能出现“怪物防御比英雄攻击还高血条怎么打都打不动”的死循环。hp max(0, self.hp - actual)这一行把血量限制到非负保证输出好看状态也干净。类属性GAME_NAME不属于任何单独实例所有角色共享同一份。访问方式可以是Character.GAME_NAME也可以是hero.GAME_NAME但改的时候建议用类名去改原因后面讲。3.2 用继承造出战士和法师继承解决的是“共性和差异并存”的难题。共性放在基类里差异放在子类里。战士和法师都继承Character于是它们天生就有血量、攻击、升级这些能力只需要自己补上独有的东西。战士加一个怒气系统攒怒气槽攒够30点能释放重击伤害更高class Warrior(Character): 战士额外拥有怒气机制 def __init__(self, name, hp, atk, defense): super().__init__(name, hp, atk, defense) self.rage 0 self.max_rage 100 def gain_rage(self, amount): 受到伤害或攻击时会积攒怒气 self.rage min(self.max_rage, self.rage amount) def use_skill(self, target): 重击消耗30怒气打出1.5倍伤害 if self.rage 30: print(f{self.name} 怒气不足当前怒气 {self.rage}/100破不了防) return 0 self.rage - 30 damage int(self.atk * 1.5) actual target.take_damage(damage) print(f{self.name} 释放重击造成 {actual} 点伤害剩余怒气 {self.rage}) return actual法师加一个法力条和火球术法力耗光就只能普攻class Mage(Character): 法师额外拥有法力值可以用火球术 def __init__(self, name, hp, atk, defense, mp): super().__init__(name, hp, atk, defense) self.mp mp self.max_mp mp def use_skill(self, target): 火球术消耗20魔法打出2倍伤害 if self.mp 20: print(f{self.name} 法力不足当前法力 {self.mp}/{self.max_mp}) return 0 self.mp - 20 damage self.atk * 2 actual target.take_damage(damage) print(f{self.name} 施放火球术造成 {actual} 点伤害剩余法力 {self.mp}) return actual这两个子类里最关键的一行是super().__init__(name, hp, atk, defense)意思是先把父类的初始化逻辑跑一遍让角色先拥有名字、血量、攻击力这堆基础属性然后自己再加怒气或法力。如果不调用它你会发现子类对象连hp都没有因为父类__init__里那几行赋值逻辑根本不会自动执行。子类里重写了use_skill这就是多态的开始同为“放技能”这个动作战士和法师的行为完全不同。只要外部代码调用这个接口Python运行时就会自动找到对应子类的方法版本继续执行不需要写if 是战士 then ... elif 是法师 then ...这种烂判断。3.3 写一个怪物类和回合制战斗流程怪物其实也是角色。为了演示“哪怕没有继承关系只要方法接口一致就能用”我给怪物单独写一个类方法名和Character保持一致class Monster: 野怪与角色类没有继承关系但接口保持一致鸭子类型 def __init__(self, name, hp, atk, defense): self.name name self.max_hp hp self.hp hp self.atk atk self.defense defense def is_alive(self): return self.hp 0 def take_damage(self, damage): actual max(1, damage - self.defense) self.hp max(0, self.hp - actual) return actual def attack(self, target): if self.is_alive() and target.is_alive(): actual target.take_damage(self.atk) print(f{self.name} 攻击 {target.name}造成 {actual} 点伤害) return actual return 0 def use_skill(self, target): # 怪物没有技能直接普攻 return self.attack(target) def __str__(self): return f{self.name} [野怪] HP {self.hp}/{self.max_hp} 攻 {self.atk} 防 {self.defense}战斗流程我设计成回合制玩家有回合内选择权怪物没有。用isinstance判断当前对象类型就能给出对应的技能选项。这是最直观、最容易读懂的写法适合新手。后面讲到工程化时我会提供更优雅的改造思路。def battle(player, enemy): 回合制战斗玩家可选普攻或技能 print(f遭遇战{player} VS {enemy}) round_num 1 while player.is_alive() and enemy.is_alive(): print(f\n----- 第 {round_num} 回合 -----) print(f玩家状态{player}) print(f敌人状态{enemy}) action input(选择操作1普通攻击2技能).strip() if action 2: if isinstance(player, Warrior): player.gain_rage(15) # 用技能也额外积攒一点怒气 player.use_skill(enemy) else: player.attack(enemy) if enemy.is_alive() and player.is_alive(): time.sleep(1) enemy.attack(player) # 战士受到攻击后积攒怒气 if isinstance(player, Warrior): player.gain_rage(10) round_num 1 print(\n 战斗结束 ) if player.is_alive(): print(f你赢了获得经验值 50) player.gain_exp(50) else: print(你输了抬回去治疗吧……)把主程序组合起来跑一场if __name__ __main__: # 选择职业 choice input(选择职业1战士2法师) if choice 2: hero Mage(name林小火, hp90, atk26, defense3, mp80) else: hero Warrior(name盾山, hp120, atk18, defense8) slime Monster(name史莱姆王, hp150, atk15, defense4) battle(hero, slime)代码输出大概是这个效果遭遇战盾山 [Lv.1] HP 120/120 攻 18 防 8 VS 史莱姆王 [野怪] HP 150/150 攻 15 防 4 ----- 第 1 回合 ----- 选择操作1普通攻击2技能1 盾山 攻击 史莱姆王造成 14 点伤害 史莱姆王[野怪] 攻击 盾山造成 7 点伤害 ...time.sleep(1)把回合节奏拉慢一点让战斗有点临场的紧张感。别小看这个小细节代码模拟和游戏心态差别就在这里。4. 新手最容易踩的四个坑4.1 可变默认参数的“共享陷阱”这是Python里经典到不能再经典的坑。很多人写类时会这样class Character: def __init__(self, name, inventory[]): # 千万别这么写 self.name name self.inventory inventory问题在于默认参数[]只用一份多个角色实例会共享同一个列表。你给hero.inventory.append(治疗药水)另一个monster.inventory里也莫名多了一瓶药水。原因很简单函数定义只执行一次默认列表在定义那一刻就被定下来了之后每次调用拿到的都是同一个对象。正确的做法是在类内部创建新容器而不是把可变对象设为默认值def __init__(self, name): self.name name self.inventory []或者更明确一点用None占位再在方法内部初始化def __init__(self, name, inventoryNone): self.name name self.inventory [] if inventory is None else inventory这个坑面试常问、实际项目经常出问题值得从第一天就形成肌肉记忆。4.2 忘写括号、忘写self、忘给属性赋值三个新手高频小bug放在一起说hero.attack是“方法对象”hero.attack()才是“调用方法”。前者打印出来是一串内存地址后者才会真正执行攻击逻辑。忘记加括号程序可能不会报错因为你只是引用而没有执行结果就是角色站桩不攻击找半天bug才发现问题。方法里忘记写self.直接写hp - damagePython会把它当局部变量处理函数一结束就被丢弃角色的血量根本没变化。此时你需要在类的方法里明白一个原则想操作“谁”的数据就必须通过self.来访问。漏掉self就像写作文漏了主语整句话的组织关系就乱了。在__init__里只给部分属性赋值其他属性到用的时候才临场self.xxx 100这在语法上合法但一旦在赋值前访问就立刻报AttributeError。更好的习惯是所有属性都在__init__里初始化哪怕暂时用不到也先给一个占位默认值比如self.status 正常。这样对象从被创建的第一刻起就是一个状态完整的对象。4.3 千万别以为Python有真正的私有属性很多学过Java或者C的人刚转Python时会问类里加个双下划线__hp是不是就私有化了答案是Python没有绝对的私有成员双下划线只是“名称改写”。具体机制是一个写成__hp的属性在外部访问时实际上被Python在内部改写成了_ClassName__hp。外部直接写hero.__hp会报错但写hero._Character__hp依然能访问到。所以这个名字改写存在的意义是“防止误触”而不是“防止偷看”。为了解决“我真的想让外部代码遵守约定减少误用”规范的做法是对不希望外部直接改的内部字段加单个下划线前缀例如self._hp。下划线是Python社区的一种约定俗成的君子协定约定是“看起来是内部使用的外部请勿直接操作”。如果你需要给外部提供修改血量的途径就明确写一个方法比如take_damage让外部通过方法去改这会把“改数据”这件事变成一个受控过程方便日后增加校验、日志、事件广播逻辑——这才是面向对象追求的真正目标。4.4 通过实例修改类属性改错地方前面提到GAME_NAME定义在类里这是类属性。访问它用hero.GAME_NAME没问题但要修改它的时候建议用Character.GAME_NAME 新名字。如果你用hero.GAME_NAME 新名字去改会发生什么Python把hero这个实例上创建了一个全新的实例属性GAME_NAME它遮蔽了类属性。其他角色打印GAME_NAME还是老名字而你自己的角色却显示新名字。数据变得不一致而且非常不明显。判断一个属性属于类还是实例核心看两点它在哪一级定义以及它天然应该全类共享还是每个实例独立。经验值是实例属性因为每个角色的经验是独立的游戏名、基础经验升级曲线这些是类属性因为它对所有人一视同仁。搞混这两者的后果就是同一个类下的角色行为不统一排查起来还很隐蔽。5. 这套系统还能怎么进化5.1 组合与聚合给角色一个背包继承解决的是“是什么”的纵向关系组合解决的是“有谁”的横向关系。一个角色拥有背包背包里有装备和道具这种关系用继承完全没有办法表达继承表达的是一种“is-a”的强关联而组合是一个“has-a”的关系是整体与部分的关系。将组合引入项目后可以这样设计class Item: def __init__(self, name, effect_value): self.name name self.effect_value effect_value def use(self, target): target.hp min(target.max_hp, target.hp self.effect_value) print(f{target.name} 使用了 {self.name}恢复 {self.effect_value} 点生命) class Backpack: def __init__(self, owner): self.owner owner self.items [] def add_item(self, item): self.items.append(item) def use_item(self, index, targetNone): item self.items.pop(index) item.use(target if target else self.owner) # 在Character.__init__里加一行 # self.backpack Backpack(self)这样做的最大好处是背包的增删逻辑被封装在Backpack内部角色类不需要关心背包怎么运作它只需要知道“我有背包包里能放东西能拿东西用”。这种思路让大系统的模块各自独立演进角色不知道背包内部如何实现背包也不知道角色战斗逻辑两者通过接口协作互相替换都不受影响。这种解耦思想是工程化开发中最核心的设计目标之一。5.2 用“接口”统一所有战斗单位现在回看战斗代码里的isinstance(player, Warrior)判断你会发现它写得很笨重。如果游戏加一个盗贼职业、一个治疗职业这种if...elif链会越来越长战斗函数越来越难维护。更优雅的做法是让所有角色类统一实现一个技能接口然后在战斗里无脑调用use_skill。现在基类还没定义use_skill战士和法师各自定义了这有个隐患万一某个子类忘了重写这个方法战斗循环里调用use_skill会直接抛AttributeError。更好的做法是在基类给一个合理的默认实现class Character: def use_skill(self, target): # 没有特殊技能时默认使用普通攻击 return self.attack(target)然后所有子类都去重写这个方法战斗循环直接调用player.use_skill(enemy)而不关心它到底是什么职业。再往后如果你想用更严格的方式约束“所有角色必须有use_skill”可以引入abc模块from abc import ABC, abstractmethod class Character(ABC): abstractmethod def use_skill(self, target): 所有角色必须实现技能逻辑这样一来所有继承Character的类如果漏掉了use_skill程序在创建实例时直接报错错误在编码阶段就被暴露而不是等到运行时才炸出来。这个机制叫“抽象基类”相当于给团队协作立了一条规则逼着所有人按接口办事。等到你的项目需要多人协作、需要别人接手你的角色类定义时你会庆幸当初在这个接口上花了时间。5.3 状态效果与事件通知从小项目走向大系统这套角色系统虽然已经能跑但离真正的小游戏还差两件事状态效果和事件同步。状态效果中毒、冰冻、护盾、眩晕、嘲讽这些都是游戏里非常常见的机制。要给系统加上这些状态正确思路是给角色加一个status_effects列表每一项是一个效果对象——它有自己的持续回合数、每回合触发逻辑、结束条件。战斗循环每回合开始前遍历角色身上的效果该扣血扣血该限制行动限制行动。这套“效果即对象”的思路本质上是把业务逻辑从角色类里抽出来让角色变得无脑而稳定。事件通知当怪物被击杀、英雄升级、生命值低于20%界面需要弹出提示任务系统需要记录进度。如果你在每个地方都手动写死打印逻辑最后代码会变成一团浆糊。工程上会用发布-订阅模式让角色在特定时刻发布事件界面、任务、统计模块各自去订阅这些事件。这也是观察者模式在游戏里的典型用途。那是不是说新手项目必须一上来就搞这些重型机制当然不是。你的第一个角色系统最重要的目标是“跑起来、看得懂、能改”。先把类、继承、方法、属性这些基础概念通过实战吃透等这套系统写熟了再逐步把这些工程化武器叠加进去你会发现每一步升级都是有目标的而不是为了模式而模式那种学习反而更省力。我个人练这种项目最深的体会是面向对象不是一种语法而是一种组织代码的思维方式。写游戏角色系统的过程就是在训练自己把现实世界的复杂系统拆成“对象—行为—协作”的过程。你可以今天写英雄明天给英雄加宠物后天给宠物加羁绊系统每一步都让旧代码在局部扩展而不是把以前写的东西推倒重来——这才是OOP真正给你带来的长期收益。

相关新闻

Linux运维利器awk:文本处理与日志分析实战指南

Linux运维利器awk:文本处理与日志分析实战指南

搞运维和系统管理的朋友,八成都有过这种经历:处理一个几百MB的日志文件,想统计某个状态码出现的次数、提取特定时间段内的访问IP、把字段按一定格式重排输出。用sed?稍显吃力;用grep?只能匹配不能计算&…

2026/10/10 5:06:26 阅读更多 →
vscode中4个json的区别和联系

vscode中4个json的区别和联系

在vscode中快捷键ctrlshiftp,然后输入setting,会出现下图几个选项 当不同设置之间出现冲突时,听谁的: Open Workspace Settings(JSON) > Open Settings(JSON) Open User Settings > Open Default Settings(JSON) Open Wo…

2026/10/10 5:06:26 阅读更多 →
ubuntu 显卡驱动/cuda/cudnn

ubuntu 显卡驱动/cuda/cudnn

显卡驱动https://www.bilibili.com/video/BV1Zc41137tU/?spm_id_from333.999.0.0&vd_sourced75fca5b05d8be06d13cfffd2f4f7ab5使用recommended的驱动,open和无open的区别在于无open更适合发挥NVIDIA显卡的全部功能和性能,特别是GPU加速计算等任务ht…

2026/10/10 5:06:26 阅读更多 →

最新新闻

缩短招聘周期:从人才画像到Offer的11个高效策略

缩短招聘周期:从人才画像到Offer的11个高效策略

招聘周期拉长,用人部门催、候选人等不起、HR夹在中间两头受气——这是过去几年我在各类企业里反复看到的真实场面。尤其遇到急招岗位,从职位发布到人选入职动辄拖上三四十天,错过业务窗口不说,还经常出现“谈好的Offer被对手截胡”…

2026/10/10 5:45:40 阅读更多 →
MyBatis动态SQL核心用法:多条件查询、批量操作与安全实践

MyBatis动态SQL核心用法:多条件查询、批量操作与安全实践

做后端几年,动态 SQL 基本是每天都要打交道的东西。业务方今天要按名称筛,明天要加时间范围,后天又要排除某几个状态,如果每换一种组合就写一条 SQL,代码量会无限膨胀。更麻烦的是,条件一变,拼接…

2026/10/10 5:45:40 阅读更多 →
C++函数传参与内存模型:对象生命周期与RAII解析

C++函数传参与内存模型:对象生命周期与RAII解析

我记得带过不少刚学编程的新同学,很多人是在“指针”“内存”“类”这三座大山面前开始动摇的。前两讲我们把语法基础过了一遍,第三讲正好站在一个分水岭上:如果只看代码表面,你写的还是C;但如果理解了函数回调机制、内…

2026/10/10 5:45:40 阅读更多 →
基于Python的多元统计分析课设源码:从K-means到PCA实战解析

基于Python的多元统计分析课设源码:从K-means到PCA实战解析

简介:这是一份面向高校生与数据学习者的多元统计分析课程设计源码包,覆盖描述性统计、回归分析、因子分析、主成分分析、k均值与层次聚类、Apriori关联规则等经典方法,每个Python脚本对应一个独立实验,从数据读取、清洗到结果输出…

2026/10/10 5:45:40 阅读更多 →
Python54-55:核心语法-数据容器-字典dict-案例

Python54-55:核心语法-数据容器-字典dict-案例

开发一个购物车管理系统,实现商品信息的添加、修改、删除、查询功能。系统使用字典结构存储商品数据,通过控制台菜单与用户交互。具体功能如下:添加购物车:用户根据提示录入商品名称、以及该商品的价格、数量,保存该商…

2026/10/10 5:45:40 阅读更多 →
开源实时协作Markdown编辑器HedgeDoc:自托管与权限管理指南

开源实时协作Markdown编辑器HedgeDoc:自托管与权限管理指南

如果你所在的环境里,协作记录一直散落在聊天记录、本地文本和邮箱附件之间,我建议你认真了解一下 HedgeDoc。它是一款开源的、基于 Web 的实时协作 Markdown 编辑器,浏览器打开就能用,也能在自己的服务器上搭建。我把团队内部的技…

2026/10/10 5:44:39 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →