python面向过程与初始面向对象编程
让我们穿越到《龙珠》世界,一起揭开 面向对象编程 的神秘面纱吧。
面向过程编程与面向对象编程
天下第一武道会
选手登记
第 22 届天下第一武道会即将召开,各路武术高手齐聚一堂,其中最受瞩目的,当属卡卡罗特(孙悟空)一行人,以及比克大魔王为首的邪恶力量。
每名选手在报名参加武道会时,都需要填写报名表。你觉得下列哪种数据类型 更适合 用于存储每名选手的个人信息呢?
整数型?浮点型?字符串?列表型?还是字典类型呢???
🤔️ 嗯……选手所填写的报名表中包含 多种信息,每条信息的 类别 与 具体内容 间存在一一对应的关系。这么看来,我们应该使用 字典 来存储信息。
😉 相信这对你来说已经是小菜一碟了。储存好选手们的信息,天下第一武道会终于可以开始啦!
决斗方式
本届武道会采取 回合制 决斗方式,即一方进攻后,攻防交换,轮到另一方进攻。如此不断重复,直到某一方 生命值降为 0 或 0 以下,判定为战败。
回合制战斗这类形式,决斗双方会不断 重复“A 攻击 B 防御、B 攻击 A 防御” 这一过程,所以我们用 循环结构 来表示,这是没有问题的。但是,决斗 直到 某一方生命值降为 0 或 0 以下才会停止,我们无法预先估计循环次数,因此比起 for
型循环,这里更适合用 while
型循环结构来表示喔。
确定了整体结构后,我们来继续思考:决斗过程是 A 攻击 B 防御、B 攻击 A 防御,然后又轮到 A 攻击 B 防御、B 攻击 A 防御。因此,循环体内最重要的两个步骤就是 发起攻击、防御攻击。
而每次有人发动攻击,都可能使防御方重伤倒地不起(生命值降为 0 或 0 以下),所以 A 打 B 之后,我们需要判断一下,此时 B 生命值是否小于等于 0。如果小于等于 0,则 B 战败、A 获胜。B 打 A 后同理。
我们将上述思路整合一下,就能画出决斗过程流程图啦:
搭好了整体框架,下面我们来逐步填充细节吧~
攻击,防御
循环体内有两大关键步骤,因此我们可以设计两个函数:
- 发起攻击函数
hit()
:接受 2 个参数,第一个参数表示攻击方,第二个参数表示攻击对象;- 防御攻击函数
defend()
:接受 2 个参数,第一个参数表示受到攻击的人,第二个参数表示受到的伤害。
发动攻击函数 hit()
比较好办,我们只要让攻击方大喝一声“哋”,接着调用 defend()
函数,让防御方防御即可。写成代码的话就是这样:
# 发动攻击
def hit(attacker, target):print('>> 【{}】发起攻击,\n'.format(attacker['name']))defend(target, attacker['ATK'])
在防御攻击函数 defend()
中,我们则可以加一些花样——卡卡罗特和比克大魔王这样的武林高手,肯定不会傻愣愣地站在原地挨打。因此我们可以设定,当某人防御攻击时,有 20% 几率完美闪避,毫发无损。
那么新的问题就来了:我们要如何体现这“20% 几率闪避”呢?
这就要用到我们在 前面 几关学习过的 random
模块中的 randint()
方法了。
randint()
方法接受两个整数,将返回包括这两个整数之间、加上两个数本身在内的所有整数。
借助 randint()
函数,我们就能设计闪避机制了。首先,我们随机生成一个 1~100 之间的整数(包括 1 和 100)。此时,它有 1% 的可能是 1,有 1% 的可能是 2,有 1% 的可能是 3……即,它有 20% 的可能小于等于 20。
所以,判定防御方是否闪避成功的问题,就可以转化为判断生成的随机数是否小于等于 20 的问题。写成代码的话就是这样:
from random import randint# 防御攻击
def defend(defender, damage):# 若生成的随机数小于等于 20,则闪避成功if randint(1, 100) <= 20:print('>> 【{}】完美躲避了攻击!\n'.format(defender['name']))# 否则扣除对应生命值else:defender['HP'] = defender['HP'] - damageprint('>> 【{}】受到 {} 点伤害...\n'.format(defender['name'], damage))
提示:这里的前缀“>> ”仅起到装饰作用。你可以根据自己的喜好设计不同的输出效果哦~
编程练习
请你根据上面分析过程,完成防御攻击函数 defend()
,并按照注释中的要求调用函数。
要求
- 防御方有 20% 几率完美闪避攻击;
- 若闪避成功,则输出 >> 【xxx】完美躲避了攻击!;否则输出 >> 【xxx】受到 xxx 点伤害。
from random import randint# 选手信息
kakarot = {'name': '卡卡罗特', 'HP': 100, 'ATK': 25}
piccolo = {'name': '比克大魔王', 'HP': 150, 'ATK': 15}# 发动攻击
def hit(attacker, target):print('>> 【{}】发起攻击,\n'.format(attacker['name']))defend(target, attacker['ATK'])# 在下面进行代码补充
# 防御攻击# 调用函数,让卡卡罗特向比克大魔王发动攻击# 调用函数,让比克大魔王向卡卡罗特发动攻击
补充后打代码为:
from random import randint# 选手信息
kakarot = {'name': '卡卡罗特', 'HP': 100, 'ATK': 25}
piccolo = {'name': '比克大魔王', 'HP': 150, 'ATK': 15}# 发动攻击
def hit(attacker, target):# print(attacker)print('>> 【{}】发起攻击,\n'.format(attacker['name']))defend(target, attacker['ATK'])# 防御攻击
def defend(target, atk):if randint(1,100) <= 20:# 如果有闪避,则完美闪避print('>> 【{}】完美躲避了攻击!'.format(target['name']))else:# 如果没有闪避,则被攻击,收到上海print('>> 【{}】受到 {} 点伤害'.format(target['name'], atk))
# 调用函数,让卡卡罗特向比克大魔王发动攻击
hit(kakarot, piccolo)
# 调用函数,让比克大魔王向卡卡罗特发动攻击
hit(piccolo, kakarot)# 输出结果为:
# >> 【卡卡罗特】发起攻击,
# >> 【比克大魔王】受到 25 点伤害
# >> 【比克大魔王】发起攻击,
# >> 【卡卡罗特】受到 15 点伤害
太棒啦!循环体内两大步骤都搞定了,最后,我们只需要把这几个“零件”组装到一起,就能让选手们展开决斗了。
不过,我们目前编写的这一版代码还存在两大问题:
第一大问题是,由于我们是用 字典类型变量 存储选手信息的,所以每新增一位选手,我们都需要 重复定义相同数据结构,多少还是有些麻烦。我们有没有什么方法,能够定义出一个通用的选手 模板 呢?
第二大问题是,我们调用 hit()
函数让 A 向 B 发动攻击时,编写出的代码是 hit(A, B)
。按照我们的语言习惯,可能会被误解为“同时攻击 A 和 B”(hit A and B)。我们有没有什么方法能够让代码更符合我们的认知习惯呢?
解决这两个问题的方法并不难。它所要用到的 Python 语法,就是我们本单元的重点——类。困难的地方在于,这次我们不仅要学习新的语法,还要学习一种新的分析问题方式——面向对象编程。
两种重要编程思想
编程届一直存在两种编程思想,一种是 面向过程,另一种是 面向对象。首先让我们来看看什么是 面向过程编程。
面向过程编程
面向过程编程 方式将程序看作 命令 的集合,按照 问题解决步骤 编写程序。我们一直以来就是用这种方式分析问题、编写程序的。
比如我们在分析决斗过程时,先将决斗过程拆解为两大步骤,为每个步骤设计函数实现,最终代码结构是这样的:
# 选手信息
kakarot = {'name': '卡卡罗特', 'HP': 100, 'ATK': 25}
piccolo = {'name': '比克大魔王', 'HP': 150, 'ATK': 15}# 发动攻击
def hit(attacker, target):pass# 防御攻击
def defend(defender, damage):pass# 展开决斗
while True:# 每回合开始,由卡卡罗特先发动攻击hit(kakarot, piccolo)# 判断此时决斗是否分出胜负if piccolo['HP'] <= 0:break# 若未分出胜负,则攻防交换,由比克大魔王发动攻击hit(piccolo, kakarot)# 判断此时决斗是否分出胜负if kakarot['HP'] <= 0:break
提示:此处代码省略了函数实现细节。
可以看到,用面向过程思想写出来的代码最大优点在于 步骤清晰。但与此同时我们也注意到:程序中的 数据 与 函数 间是十分松散的,只有编写代码的我们心里清楚 hit()
函数中的 attacker
参数与 target
参数,实际上是由 'name'
键、'HP'
键和 'ATK'
键构成的字典类型变量。
理想状况下我们当然可以记住每个变量的类型、结构。可是,如果问题规模不断扩大,我们又该怎么办呢?
比如对于一场真实的武道会来说,我们不仅要存储选手们的信息,还要存储主持人、裁判等 不同身份 的人的信息;我们不仅要表现决斗过程,还要表现赛前抽签、主持人主持比赛、裁判判决比赛等过程……此时若继续采用 面向过程编程 思想,那我们编写出的程序势必会结构混乱。即使把它们拆解成一个个模块,也是治标不治本。
如果想“治本”,则需要转变看待问题的角度,尝试用 面向对象编程 思想重新审视周遭的一切。
面向对象编程
想弄明白什么是 面向对象编程,首先我们要明白什么是 对象。
咳咳,这里的“对象”指的肯定不是伴侣,而是 具有一系列特征和行为的个体。我们需要解决的问题,则可看作 对象与对象之间的交互。比如在天下第一武道会中,每名选手都是独立的个体,可视作一个 对象。一场决斗是两位选手之间的对决,即两个对象之间的交互。
进一步地我们发现,虽然 对象 A 和 对象 B 是独立的个体,但他们都有姓名、生命值、攻击力这三样 特征,都有 发动攻击 和 防御攻击 这两样行为。因此我们可以说他们是同一 类 的。这里不妨为它取名为 选手类。
运用这一思想,我们能够轻松地应对大规模问题——
由于主持人、裁判、选手之间 特征 和可以做出的 行为 各不相同,因此我们可以定义出三大 类 描述他们,后续任务无非就是将这三个类写成代码:
不知道你发现了吗?在用 面向对象编程 思想分析问题时,我们并没有关注 问题解决步骤,而是从 对象 出发,先弄清楚什么样的对象能做什么事,再从中归纳总结出几大 类,每个 类 都有自己着自己的特征与行为。
这就是 面向对象编程 与 面向过程编程 的最大区别。面向对象编程 方法将编程视作 对象 的集合,从 对象与对象间的交互 角度出发思考问题。
这种思维方式更贴近我们平时认知世界的直觉。因此即使我们不明白类相关的语法规则和背后的实现逻辑,也能够按照我们的生活经验推断出代码对应的含义。比如对于下面这段代码:
kakarot = Player('卡卡罗特', 100, 25)
piccolo = Player('比克大魔王', 150, 15)kakarot.hit(piccolo)
不妨猜猜看,代码第三行 kakarot.hit(piccolo)
描述了一种怎样的行为呢?
A:
kakarot
攻击piccolo
B:piccolo
攻击kakarot
C:kakarot
和piccolo
同时受到了攻击答案当然选A了。是不是很简单
从“kakarot”、“hit”、“piccolo”这三个词的顺序我们不难推断出,这行代码是在描述 kakarot
攻击 piccolo
(Kakarot hit Piccolo)。这就是面向对象编程的魅力所在!
面向对象编程的概念就介绍到这里啦。
类 是抽象的模板,对象 是具象的个体。上述过程中共出现了三位角色,分别是大勇、卡卡罗特、比克大魔王,所以涉及到的对象就是他们三人。而“主持人”与“选手”是他们所属的 类。
改用另一种思维方式分析问题是一项需要不断练习才能真正领会、掌握的事,不能一蹴而就。所以本关我们重在梳理 决斗过程 逻辑,并简要了解了 面向对象编程 的概念,知道了它和我们传统的 面向过程编程 方式间的区别:
编程练习_回合制决胜负
请你根据 决斗过程流程图 和注释中的提示信息,补全代码,让卡卡罗特和比克大魔王展开决斗吧!你也可以在此基础上修改,让决斗过程更加丰富有趣哦。
决斗说明
- 决斗采取 回合制;
- 由卡卡罗特先发动攻击。
决斗过程流程图
from random import randint# 选手信息
kakarot = {'name': '卡卡罗特', 'HP': 100, 'ATK': 25}
piccolo = {'name': '比克大魔王', 'HP': 150, 'ATK': 15}# 发动攻击
def hit(attacker, target):print('>> 【{}】发起攻击,\n'.format(attacker['name']))defend(target, attacker['ATK'])# 防御攻击
def defend(defender, damage):# 若生成的随机数小于等于 20,则闪避成功if randint(1, 100) <= 20:print('>> 【{}】完美躲避了攻击!\n'.format(defender['name']))# 否则扣除对应生命值else:defender['HP'] = defender['HP'] - damageprint('>> 【{}】受到 {} 点伤害...\n'.format(defender['name'], damage))# 展开决斗
while True:# 每回合开始,由卡卡罗特先发动攻击hit(kakarot, piccolo)# 判断此时决斗是否分出胜负if piccolo['HP'] <= 0:print('{}获胜'.format(kakarot['name']))break# 若未分出胜负,则攻防交换,由比克大魔王发动攻击hit(piccolo, kakarot)# 判断此时决斗是否分出胜负if kakarot['HP'] <= 0:print('{}获胜'.format(piccolo['name']))break# 输出结果为:(获胜结果是随机的)
# >> 【卡卡罗特】发起攻击,
# >> 【比克大魔王】受到 25 点伤害...
# >> 【比克大魔王】发起攻击,
# >> 【卡卡罗特】受到 15 点伤害...
# >> 【卡卡罗特】发起攻击,
# >> 【比克大魔王】受到 25 点伤害...
# >> 【比克大魔王】发起攻击,
# >> 【卡卡罗特】受到 15 点伤害...
# >> 【卡卡罗特】发起攻击,
# >> 【比克大魔王】受到 25 点伤害...
# >> 【比克大魔王】发起攻击,
# >> 【卡卡罗特】受到 15 点伤害...
# >> 【卡卡罗特】发起攻击,
# >> 【比克大魔王】受到 25 点伤害...
# >> 【比克大魔王】发起攻击,
# >> 【卡卡罗特】受到 15 点伤害...
# >> 【卡卡罗特】发起攻击,
# >> 【比克大魔王】受到 25 点伤害...
# >> 【比克大魔王】发起攻击,
# >> 【卡卡罗特】受到 15 点伤害...
# >> 【卡卡罗特】发起攻击,
# >> 【比克大魔王】受到 25 点伤害...
# 卡卡罗特获胜
编程练习_决斗时喊出技能名不是很酷吗
不好了不好了,比克大魔王率领一众小弟包围了武道会主办方,说:“哼,区区‘攻击力 15’怎能体现出我强大的招式呢?我提议,在登记信息时将我们的绝招也登记上去,决斗时各自报出技能。谁敢不从?”
主办本想拉着卡卡罗特一行人撑腰,没想到小悟空连连点头:“对呀,喊出技能名多酷哇。就这么办吧!”
哎……看来只能麻烦你改进一下之前的代码了。
要求
- 选用 合适 的数据类型存储每位选手信息;
- 编写
hit()
函数,该函数接受两个参数attacker
和target
,表示attacker
随机使用自己任意一个技能,向target
发动攻击。
另外,进攻方在攻击时,要喊出自己使用了什么技能,就像这样:
hit(kakarot, piccolo)# 输出:>> 【卡卡罗特】使出残象拳向【比克大魔王】发动攻击,
数据说明
卡卡罗特(kakarot)
- 生命值(HP):100
- 技能(SKILLS):
- 残象拳:威力 10
- 八手拳:威力 15
- 变身赛亚人:威力 50
比克大魔王(piccolo)
- 生命值(HP):150
- 技能(SKILLS):
- 魔光线:威力 10
- 魔光炮:威力 15
- 爆裂魔光炮:威力 20
# 请在此处登记卡卡罗特选手信息# 请在此处登记比克大魔王选手信息# 请在此处定义 hit() 函数# 调用 hit() 函数
优化后代码(非固定答案):
import random
# 请在此处登记卡卡罗特选手信息
kakarot = {'name':'卡卡罗特','HP':'100','技能':[{'name':'残象拳','damage':'80'},{'name':'八手拳','damage':'15'},{'name':'变身赛亚人','damage':'50'}]
}
# 请在此处登记比克大魔王选手信息
piccolo = {'name':'比克大魔王','HP':'150','技能':[{'name':'魔光线','damage':'10'},{'name':'魔光炮','damage':'10'},{'name':'爆裂魔光炮','damage':'20'}]
}# 请在此处定义 hit() 函数
def hit(attacker, target):# 技能skill = random.choice(attacker['技能'])['name']print('>> 【{}】使出{}向【{}】发动攻击,'.format(attacker['name'], skill, target['name']))
# 调用 hit() 函数
hit(kakarot, piccolo)
下章预告:python的 类 和 对象
下章我来带你在动手编写代码过程中,逐步加深对 类 和 对象 的理解。
我们要如何定义选手类?选手与选手间的交互又要如何实现?这些问题在下一关都会得到解答。我们不见不散!
相关文章:

python面向过程与初始面向对象编程
让我们穿越到《龙珠》世界,一起揭开 面向对象编程 的神秘面纱吧。 面向过程编程与面向对象编程 天下第一武道会 选手登记 第 22 届天下第一武道会即将召开,各路武术高手齐聚一堂,其中最受瞩目的,当属卡卡罗特(孙悟…...

vue3 实现自定义指令封装 --- 通俗易懂
1、局部自定义指令 1.1 在<script setup>定义组件内的指令,任何以v开头的驼峰式命名的变量都可以被用作一个自定义指令 <template><div><h3>使用自定义指令</h3><div>########################## start 局部自定义指令</d…...

5.31.15 使用图像到图像转换和 YOLO 技术对先前的乳房 X 光检查结果中的异常进行早期检测和分类
在本研究中,我们研究了基于 You-Only-Look-Once (YOLO) 架构的端到端融合模型的有效性,该模型可同时检测和分类数字乳房 X 光检查中的可疑乳腺病变。包括四类病例:肿块、钙化、结构扭曲和正常,这些病例来自包含 413 个病例的私人数…...

题解web
1.[LitCTF 2023]Follow me and hack me 1)进入题目环境,提示get传参,post传参 2)看看源码,也没啥 3)直接用hackbar,传入对应参数即可得到FLAG 3)但是扫描出来它后端还有东西&#x…...

在keil5中打开keil4工程的方法
文章目录 1. 打开文件 2. 安装旧版本包 3. 在keil4中打开keil5工程 1. 打开文件 在keil5 MDK的环境下,打开keil4的工程文件,会弹出下图所示的窗口: 参考官网的解释这两个方法分别为: 1. 使用MDK 版本 4 Legacy Pack时&#x…...
【代码随想录算法训练营第37期 第二十四天 | LeetCode77. 组合】
代码随想录算法训练营第37期 第二十四天 | LeetCode77. 组合 一、77. 组合 解题代码C: class Solution { private:vector<vector<int>> result;vector<int> path;void backtracking(int n, int k, int startIndex){if(path.size() k){result.p…...
探索Linux中的`tree`命令:目录结构的可视化利器
探索Linux中的tree命令:目录结构的可视化利器 在Linux系统中,管理文件和目录结构是一项日常任务。当我们需要快速查看目录的层次结构时,tree命令无疑是一个强大而直观的工具。本文将详细介绍tree命令的功能、用法以及一些实用的选项。 一、…...
ES 面试手册
Elasticsearch是什么? Elasticsearch是一个基于Lucene的搜索和分析引擎,它提供了一个分布式、多租户能力的全文搜索引擎,具有HTTP Web界面和无模式JSON文档。 Elasticsearch中的倒排索引是什么? 倒排索引是搜索引擎的核心结构&a…...
Mybatis缓存的生命周期、使用的特殊情况
以下场景均在Spring Boot程序中,并非手动创建SqlSession使用。 在回答这个问题之前,我们先来回顾一下,Mybatis的一级二级缓存是啥。 一级二级缓存 是什么 一级缓存(本地缓存):一级缓存是SqlSession级别的…...
day 37 738.单调递增的数字
738. 单调递增的数字 当且仅当每个相邻位数上的数字 x 和 y 满足 x < y 时,我们称这个整数是单调递增的。 给定一个整数 n ,返回 小于或等于 n 的最大数字,且数字呈 单调递增 。 示例 1: 输入: n 10 输出: 9示例 2: 输入: n 1234 输…...
【加密与解密】【01】网络安全体系
网络通信OSI模型 物理层(Physical)链路层(DataLink)网络层(Network)传输层(Transport)会话层(Session)表示层(Presentation)应用层&a…...

nvm,node不是内部命令,npm版本不支持问题(曾经安装过nodejs)
nvm安装后nvm -v有效,node指令无效 环境变量配置无问题 推荐方案 下载你需要的node版本 Index of /dist/ (nodejs.org) 下载后解压到你的nvm存储版本的位置 cmd进入切换你的使用版本(此时你的nodejs是从网上下载的,npm文件是存在的&…...
从入门到精通:基础IO
引言 在编程的世界里,文件输入输出(IO)是与操作系统交互的重要方式。无论你是开发应用程序、处理数据,还是管理系统资源,掌握文件IO操作都是必不可少的。本篇博客将带你深入了解C语言中的基础IO操作,从入门…...

网络空间安全数学基础·多项式环与有限域
5.1 多项式环(掌握) 5.2 多项式剩余类环(理解) 5.3 有限域(熟练) 5.1 多项式环 定义:设F是一个域,称是F上的一元多项式. 首项:如果an≠0,则称 a…...

路由器重启真的好吗?多久重启一次更好?
前言 小白前段时间发现自己家的OpenWRT软路由上网特别慢,有时候通话还有点卡顿。 然而有个朋友用的普通路由器也有类似的问题,而且有时候根本上不去网。 解决的办法很简单:重启路由器。 重启路由器? 但路由器重启是真的好吗&a…...

删除目录
自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 删除目录可以通过使用os模块提供的rmdir()函数实现。通过rmdir()函数删除目录时,只有当要删除的目录为空时才起作用。rmdir()函数的基本语…...

HCIP-Datacom-ARST自选题库__BGP/MPLS IP VPN判断【10道题】
1.部署BGP/MPLSIP VPN时,当两个VPN有共同的站点,则该共同站点一定不能与两个VPN其他站点使用重叠的地址空间。 2.如图所示,运营商BGP/MPLSIP VPN骨干网通过LDP构建LSP,若想实现用户X两个站点之间通过BGP/MPLSIP VPN网络互通,则PE1和PE2之间必…...

【Go语言精进之路】构建高效Go程序:掌握变量、常量声明法则与iota在枚举中的奥秘
🔥 个人主页:空白诗 文章目录 引言一、变量1.1 基础知识1.2 包级变量的声明形式深入解析📌 声明并同时显式初始化📌 声明但延迟初始化📌 声明聚类与就近原则 1.3 局部变量的声明形式深入探讨📌 延迟初始化的…...
python记录之bool
在Python中,bool 是一个内置的数据类型,用于表示逻辑值:True 或 False。虽然这个数据类型看起来很简单,但在编程中它扮演着至关重要的角色,特别是在条件语句、循环以及许多其他逻辑操作中。以下是对Python bool 的深入…...

加密经济浪潮:探索Web3对金融体系的颠覆
随着区块链技术的快速发展,加密经济正在成为全球金融领域的一股新的浪潮。而Web3作为下一代互联网的代表,以其去中心化、可编程的特性,正深刻影响着传统金融体系的格局和运作方式。本文将深入探讨加密经济对金融体系的颠覆,探索We…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...

Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...
Spring Boot + MyBatis 集成支付宝支付流程
Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例(电脑网站支付) 1. 添加依赖 <!…...
多元隐函数 偏导公式
我们来推导隐函数 z z ( x , y ) z z(x, y) zz(x,y) 的偏导公式,给定一个隐函数关系: F ( x , y , z ( x , y ) ) 0 F(x, y, z(x, y)) 0 F(x,y,z(x,y))0 🧠 目标: 求 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z、 …...
深入浅出JavaScript中的ArrayBuffer:二进制数据的“瑞士军刀”
深入浅出JavaScript中的ArrayBuffer:二进制数据的“瑞士军刀” 在JavaScript中,我们经常需要处理文本、数组、对象等数据类型。但当我们需要处理文件上传、图像处理、网络通信等场景时,单纯依赖字符串或数组就显得力不从心了。这时ÿ…...