16. 第十六章 类和函数

16. 类和函数

现在我们已经知道如何创建新的类型,
下一步是编写接收用户定义的对象作为参数或者将其当作结果用户定义的函数.
本章我会展示'函数式编程风格', 以及两个新的程序开发计划.
本章的代码示例可以从↓下载.
https://github.com/AllenDowney/ThinkPython2/blob/master/code/Time1.py
练习的解答在↓.
https://github.com/AllenDowney/ThinkPython2/blob/master/code/Time1_soln.py
16.1 时间
作为用户定义类型的另一个例子, 我们定义一个叫Time的的类, 用于记录一天里的时间. 类定义如下:
class Time:"""Represents the time of day.attributes: hour, minute, second"""
我们可以创建一个Time对象并给其属性小时数, 分钟数和秒钟数赋值:
time = Time()
time.hour = 11
time.minute = 59
time.second = 30
Time对象的状态图参见图16-1.

2023-04-17_00001

作为练习, 编写一个叫作print_time的函数, 接收一个Time对象作为形参
并以'hour:minute:second'的格式打印它.
提示: 格式序列'%.2d'可以以最少两个字符打印一个整数, 如果需要, 它会在前面添加前缀0.
class Time:"""Represents the time of day.attributes: hour, minute, second"""def print_time(time_obj):print('%.2d:%.2d:%.2d' % (time_obj.hour, time_obj.minute, time_obj.second))def main():time = Time()time.hour = 11time.minute = 59time.second = 30print_time(time)if __name__ == '__main__':main()
编写一个布尔函数is_after, 接收两个Time对象, t1和t2, 
并若t1在t2时间之后, 则返回True, 否则返回False. 
挑战不许使用if表达式.
class Time:"""Represents the time of day.attributes: hour, minute, second"""def print_time(time_obj):print('%.2d:%.2d:%.2d' % (time_obj.hour, time_obj.minute, time_obj.second))def main():time = Time()time.hour = 11time.minute = 59time.second = 30print_time(time)time2 = Time()time2.hour = 11time2.minute = 59time2.second = 32res = is_after(time, time2)print(res)def is_after(t1, t2):# t1的时间t1_count = t1.hour * 60 * 60 + t1.minute * 60 + t1.second# t2的时间t2_count = t2.hour * 60 * 60 + t2.minute * 60 + t2.secondprint(t1_count, t2_count)# t1比t2大返回True, 使用短路运算.return t1_count > t2_count or Falseif __name__ == '__main__':main()
16.2 纯函数
在下面几节中, 我们会编写两个用来增加时间值的函数.
它们展示了两种不同类型的函数: 纯函数和修改器. 
它们也展示了我会称为'原型和补丁'(prototype and patch)的开发计划.
这是一种对应复杂问题的方法, 从一个简单的原型开始, 并逐渐解决更多的复杂情况.下面是add_time的一个简单原型:
def add_time(t1, t2):sum = Time()sum.hour = t1.hour + t2.hoursum.minute = t1.minute + t2.minutesum.second = t1.second + t2.secondreturn sum
这个函数创建一个新的Time对象, 初始化它的属性, 并返回这个新对象的一个引用.
这个被称为一个'纯函数', 因为它除了返回一个值之外, 并不修改作为实参传入的任何对象, 
也没有任何如显示值或获得用户输入之类的副作用.为了测试这个函数, 我将创建两个Time对象:
start, 存放一个电影( Monty Python and the Holy Grail)的开始时间;
duration, 存放电影的播放时间, 在这里是1小时35分钟.add_time计算出电影何时结束.
>>> start = Time()
>>> start.hour = 9
>>> start.minute = 45
>>> start.second = 0>>> duration = Time()
>>> duration.hour = 1
>>> duration.minute = 35
>>> duration.second = 0>>> done = add_time(start, duration)
>>> print_time(done)
10:80:00
结果10:80:00可能并不是你所期望的.
问题在于这个函数并没有处理好秒数或者分钟数超过60的情况.
当发生时, 我们需要将多余的秒数'进位'到分钟数, 将多余的分钟数'进位'到小时数.下一个是改进的版本:
def add_time(t1, t2):sum = Time()sum.hour = t1.hour + t2.hoursum.minute = t1.minute + t2.minutesum.second = t1.second + t2.secondif sum.second >= 60:sum.second -= 60sum.minute += 1if sum.minute >= 60:sum.minute -= 60sum.hour += 1return sum
虽然这个函数是正确的, 它已经开始变大了. 
我们会在后面看到一个更短的版本.
16.3 修改器
有时候用函数修改传入的参数是很有用的. 在这个情况下, 修改对调用者是可见的.
这样的工作的函数称为修改器(modifile).
函数increment给一个Time对象增加指定的秒数, 可以自然地写为一个修改器.
下面是一个初稿:
# 给时间对象增加秒数.
def increment(time, second):time.second += secondsif time.second >= 60:time.second -= 60time.minute += 1if time.minute >= 60:time.minute -= 60time.hour += 1
第一行进行基础操作; 后面的代码处理我们前面看到的特殊情况.
这个函数正确吗? 如果seconds比60大很多, 会发生什么? (时间不是所期望的.)在那种情况下, 只进位一次是不够的; 我们需要重复进位, 知道time.second比60.
一个办法是使用while语句替代if语句. 那样会让韩素变正确, 但并不很高效.作为练习, 编写正确的increment版本, 并不包含任何循环.
class Time:""""""def print_time(time_obj):print('%.2d:%.2d:%.2d' % (time_obj.hour, time_obj.minute, time_obj.second))def increment(time, seconds):time.second += seconds# divmod求余数, (商, 余数)# 设置分钟与秒quotient, remainder = divmod(time.second, 60)time.second = remaindertime.minute += quotient# 小时与分钟quotient, remainder = divmod(time.minute, 60)time.hour += quotienttime.minute = remainderreturn timedef main(seconds):time_obj = Time()# 为time对象赋值属性time_obj.hour = 11time_obj.minute = 59time_obj.second = 30res = increment(time_obj, seconds)print_time(res)if __name__ == '__main__':main(9999)  # 14:46:09
任何可以使用修改器做到的功能都可以使用纯函数实现.
事实上, 有的编程语言只允许使用纯函数.
有证据表明使用纯函数的程序比使用修改器的程序开发更快, 错误更少.
但有时候修改器还是很方便的, 并且函数式程序的运行效率不那么高,总的来说, 我推荐你只要合理的时候, 都尽量编写纯函数, 而只在有绝对说服力的原因时才使用修改器.
这种方法可以称为'函数式编程风格'.
作为练习, 写一个incrment的纯函数版本, 创建并返回一个新的Time对象而不是修改参数.
(纯函数不修改传入参数的值, 修改器修改传入参数的值.)
提示: 在函数中新建Time对象, 为这个对象赋值属性, 最后返回这个新对象.
class Time:""""""def print_time(time_obj):print('%.2d:%.2d:%.2d' % (time_obj.hour, time_obj.minute, time_obj.second))def increment(time, seconds):# 新建time对象new_time = Time()# 总秒数sum_second = time.second + seconds# divmod求余数, (商, 余数)# 求分钟与秒minute, second = divmod(sum_second, 60)# 总分钟sum_minute = time.minute + minute# 求小时与分钟hour, minute = divmod(sum_minute, 60)# 为新对象设置属性new_time.second = secondnew_time.minute = minutenew_time.hour = time.hour + hourreturn new_timedef main(seconds):time_obj = Time()# 为time对象赋值属性time_obj.hour = 11time_obj.minute = 59time_obj.second = 30res = increment(time_obj, seconds)print_time(res)if __name__ == '__main__':main(9999)  # 14:46:09
16.4 原型和计划
刚才我展示的开发计划为'原型和补丁'.
对每个函数, 我编写一个可以进行基本计算的原型, 再测试它, 从中发现错误并打补丁.这种方法在对问题的理解并不深入时尤其有效.
但增量地修改可能会导致代码过度复杂(因为它们需要处理很多特殊情况),
并且也不够可靠(因为很难知道你是否已经找到了所有的错误).
另一种方法是'有规划开发'(designed devwlopment).
对问题有更高阶的理解能够让编程简单得多.
在上面的问题中, 如果更深入地理解, 可以发现Time对象实际上是六十进制数里的3位数
(参见http://en.wikipedia.org/wiki/Sexagesimal)!
second属性是'个位数', minute属性是'60位数', 而hour属性是'360位数'.
在编写add_time和increment时, 我们实际上是在六十进制上进行加减, 因此才需要从一位到另一位.
这个观察让我们可以考虑整个问题的另一个中解决方法-我们将Time对象转换为整数, 
并利用计算机知道如何做整数运行的事实.
def time_to_int(time):minutes = time.hour * 60 + time.minteseconds = mintes * 60 + time.secondreturn seconds
而下面是一个将整数转换回Time对象的函
(记着divmod函数将第一个参数除以第二个参数, 并以元组的形式返回商和余数):
def int_to_time(seconds):time = Time()minutes, time.second = divmod(seconds, 60)time.hour, time.minute = divmod(minutes, 60)return time
你可能会思考一下, 并运行一些测试, 来说服自己这些函数是正确的.
一种测试它们的方法是对很多x值检查 time_to_int(int_to_time(x)) == x.
这是一致性检验的一个例子.
一旦确认他们是正确的, 就可以使用他们重写add_time:
def add_time(t1, t2):# 将时间对象转换为秒seconds = timr_to_int(t1) + time_to_int(t2)# 将秒转换为时间对象return int_to_time(seconds)
这个版本比最初版本短的多, 并且也很容易检验.
作为练习, 使用time_to_int和int_to_time重写increment函数.
class Time:""""""def print_time(time_obj):print('%.2d:%.2d:%.2d' % (time_obj.hour, time_obj.minute, time_obj.second))def time_to_int(time):minutes = time.hour * 60 + time.minuteseconds = minutes * 60 + time.secondreturn secondsdef int_to_time(seconds):time = Time()minutes, time.second = divmod(seconds, 60)time.hour, time.minute = divmod(minutes, 60)return timedef increment(time, seconds):# 将时间对象转换为秒seconds = time_to_int(time) + seconds# 将秒转换为时间对象return int_to_time(seconds)def main(seconds):time_obj = Time()# 为time对象赋值属性time_obj.hour = 11time_obj.minute = 59time_obj.second = 30res = increment(time_obj, seconds)print_time(res)if __name__ == '__main__':main(9999)  # 14:46:09
从某个角度看, 在六十进制和十进制之间来会转换比只处理时间更难.
进制转换更加抽象; 我们对时间值的直觉更好.但如果我们将时间看作六十进制数, 并做好编写转化函数(time_to_int和int_to_time)的先期投入,
就能得到一个更短, 更可读, 也更可靠的函数.它也让我们今后更容易添加功能. 
(将时间表示为六十进制数并实现转换函数可以为今后添加更多功能提供方便,
因为将时间表示为六十进制数可以使得时间的处理更加统一化, 简化了程序实现的复杂性.)例如, 假设将两个Time对象相减来获取它们之间的时间间隔.
简单得做法是使用借位实现减法. 而使用转换函数则更简单且更容易正确.讽刺的是, 有时候把一个问题弄的更难(或者更通用)
反而会让他更简单(因为会有更少的特殊情况以及更少的出错机会).
16.5 调试
一个Time对象但minute当second的值在060之间(包好0但不包含60)以及hour是正值时, 是合法的.
hour和minute应当是整数值, 但我们也许需要允许second拥有小数值.这些需求称为'不变式', 因为他们应当总为真.
换句话说, 如果它们不为真, 则一定有什么地方出错了.编写代码来检查不变式可以帮你探测错误并找寻它们的根源.
例如, 你可以写一个像valid_time这样的函数, 接收Time对象, 并在它违反了一个不变式时, 返回False:
def valid_time(time):# 时分秒如果大于0, 返回False.if time.hour < 0 or time.minute < 0 or time.second < 0:return Faalse# 时分如果大于等于60, 返回False.if time.minute >= 60 time.second >= 60:return Falsereturn True
接着在每个函数的开头, 可以检查参数, 确保它们是有效的:
def add_time(t1, t2):if not valid_time(t1) or not valid_time(t2):raise ValueRrror('invalid Time object in add_time')seconds = time_to_int(t1) + time_to_int(t2)return int_to_time(seconds)
或者可以使用一个assert语句.
它会检查一个给定的不变式, 并但检查失败时抛出异常:
def add_time(t1, t2):# asser后面的表达式结果必须为正assert valid_time(t1) and valid_time(t2)seconds = time_to_int(t1) + time_to_int(t2)return int_to_time(seconds)
assert语句很有用, 因为它们区分了处理普通条件的代码和检查错误的代码.
16.6 术语表
原型和补丁(prototype and patch): 一种开发计划模式, 先编写程序的粗略原型, 并测试, 则找到错误时更正.有规划开发(planned development): 一种开发计划模式, 先对问题有了高阶的深入理解,并且比增量开发或者原型开发有更多的规划.纯函数(pure function): 不修改任何形参对象的函数. 大部分纯函数都有返回值.修改器(modifier): 修改一个或多个形参对象的函数. 大部分修改器都不返回值, 也就是返回None.函数式编程风格(functional proframming style): 一种编程风格, 其中大部分函数都是存函数.不变式(invariant): 在程序的执行过程中应当总是为真的条件.assert语句(assert statement): 一种检查某个条件, 如果检查失败则抛出异常的语句.
16.7 练习
本章中的代码示例可以从↓下载.
https://github.com/AllenDowney/ThinkPython2/blob/master/code/Time1.py 
这些练习的解答可以从↓下载.
https://github.com/AllenDowney/ThinkPython2/blob/master/code/Time1_soln.py
1.练习1
编写一个函数mul_time接收一个Time对象以及一个整数, 返回一个新的Time对象,
包含原始时间和整数的乘积. (时间对象转为秒 * 整数)然后使用mul_time来编写一个函数, 接收一个Time对象表示一场赛车的结束时间, 
以及一个表示距离的数字, 并返回一个Time对象表达平均节奏(每英里花费的时间).(正赛的距离不能少于305公里, 不能大于320公里, 时间不能少于1个小时10分钟, 不能大于2个小时.
1千米(公里)=0.621371192237英里)
import copyclass Time:""""""def print_time(time_obj):print('%.2d:%.2d:%.2d' % (time_obj.hour, time_obj.minute, time_obj.second))def time_to_int(time):minutes = time.hour * 60 + time.minuteseconds = minutes * 60 + time.secondreturn secondsdef mul_time(t1, num):t2 = copy.copy(t1)# 将时间转为十进制整数seconds = time_to_int(t2)# 乘积t2.product = seconds * numreturn t2def main(num):time_obj = Time()# 为time对象赋值属性time_obj.hour = 11time_obj.minute = 59time_obj.second = 30t2 = mul_time(time_obj, num)print_time(t2)print(t2.product)  # 388530if __name__ == '__main__':main(9)  
import copyclass Time:""""""def print_time(time_obj):print('%.2d:%.2d:%.2d' % (time_obj.hour, time_obj.minute, time_obj.second))def time_to_int(time):minutes = time.hour * 60 + time.minuteseconds = minutes * 60 + time.secondreturn secondsdef mul_time(t1, mile):t2 = copy.copy(t1)# 将时间转为十进制整数, 比赛的总秒数.seconds = time_to_int(t2)# 车每秒跑的距离 0.02773... 英里distance = mile / seconds# 一公里需要的时间 36.059... 秒t2.average_time = 1 / distancereturn t2def main(num):time_obj = Time()# 比赛时间time_obj.hour = 1time_obj.minute = 59time_obj.second = 30# 公路转英里 320 --> 198.83mile = num * 0.621371192237t2 = mul_time(time_obj, mile)print('每英里花费%.3f秒!' % t2.average_time)  # 每英里花费36.059秒!if __name__ == '__main__':# 比赛的公里数main(320)
2. 练习2
datetime模块提供了time对象, 和本章中的Time对象类似, 但它们提供了更丰富的方法和操作符.
在https://docs.python.org/3/library/datetime.html阅读相关文档.1. 使用datetime模块来编写一个程序获取当前日期并打印出今天是周几.2. 编写一个程序接收生日作为输入, 并打印出用户的年龄, 以及到他们下一次生日还需要的天数, 小时数, 分钟数和秒数.3. 对于生于不同天的两个人, 总有一天, 一个人的年龄是另一个人的两倍.我们称这是他们的'双倍日'. 编写一个程序接收两个生日, 并计算出它们的'双倍日'.(数学不好不写了...)
4. 在增加一点挑战, 编写一个更通用的版本, 计算一个人比另一个人大n倍的日子(n倍日).
解答:  https://github.com/AllenDowney/ThinkPython2/blob/master/code/double.py
# 计算今天是星期几
import datetime# 获取今天的日期对象
today = datetime.date.today()
print(today)  # 2023-04-18# 计算今天是星期几
weekday = today.weekday()
# 输出0-6, 0时星期1
print('今天是星期%s.' % weekday + 1)  # 今天是星期1.
# 计算离下一次生日的时间
from datetime import datetimedef main():print("今天是星期", end='')today = datetime.today()print(today.weekday() + 1)# s = input('以"年-月-日"的格式输入你的生日: ')s = '1997-03-26'# 按%Y-%m-%d 年月日格式生成日期对象, 连字符可以自定义, 对应上面的字符串即可.bday = datetime.strptime(s, '%Y-%m-%d')# 替换日期对象中的年份为今年next_bday = bday.replace(year=today.year)# 如果今天的日期比生日大, 则说明今年生日已经过了, 要到下一年才过生日, 年份加1if next_bday < today:next_bday = next_bday.replace(year=today.year + 1)# date()方法展示日期.print("你的下一个生日为: %s." % next_bday.date())# 计算离生日还有多少天until_next_bday = next_bday - today# days展示时间print('离生日还有%s天.' % until_next_bday.days)age = today.year - bday.yearprint("你现在的年龄:%s岁." % age)if __name__ == '__main__':main()
# 计算双倍日
from datetime import datetimedef main():print("在这些日期出生的人:")bday1 = datetime(day=11, month=5, year=1967)bday2 = datetime(day=11, month=10, year=2003)print(bday1.date())print(bday2.date())print("双倍日是:", end='')# 小的给d1d1 = min(bday1, bday2)# 大的日期给d2d2 = max(bday1, bday2)# 计算两个人的年龄差.dd = d2 + (d2 - d1)print(dd.date())print('年纪大的活了%s天.' % (dd - d1).days)print('年纪小的活了%s天.' % (dd - d2).days)if __name__ == '__main__':main()

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

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

相关文章

java程序在运行过程各个内部结构的作用

一&#xff1a;内部结构 一个进程对应一个jvm实例&#xff0c;一个运行时数据区&#xff0c;又包含多个线程&#xff0c;这些线程共享了方法区和堆&#xff0c;每个线程包含了程序计数器、本地方法栈和虚拟机栈接下来我们通过一个示意图介绍一下这个空间。 如图所示,当一个hell…

11.泛型、trait和生命周期(上)

标题 一、泛型数据的引入二、改写为泛型函数三、结构体/枚举中的泛型定义四、方法定义中的泛型 一、泛型数据的引入 下面是两个函数&#xff0c;分别用来取得整型和符号型vector中的最大值 use std::fs::File;fn get_max_float_value_from_vector(src: &[f64]) -> f64…

代码随想录-Day31

455. 分发饼干 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 i&#xff0c;都有一个胃口值 g[i]&#xff0c;这是能让孩子们满足胃口的饼干的最小尺寸&#xff1b;并且每块饼干 j&#xff0c;都…

vs+qt5.0 使用poppler 操作库

Poppler 是一个用来生成 PDF 的C类库&#xff0c;从xpdf 继承而来。vs编译库如下&#xff1a; vs中只需要添加依赖库即可 头文件&#xff1a;

【UE5|水文章】在UMG上显示帧率

参考视频&#xff1a; https://www.youtube.com/watch?vH_NdvImlI68 蓝图&#xff1a;

数值分析笔记(二)函数插值

函数插值 已知函数 f ( x ) f(x) f(x)在区间[a,b]上n1个互异节点 { x i } i 0 n \{{x_i}\}_{i0}^{n} {xi​}i0n​处的函数值 { y i } i 0 n \{{y_i}\}_{i0}^{n} {yi​}i0n​&#xff0c;若函数集合 Φ \Phi Φ中函数 ϕ ( x ) \phi(x) ϕ(x)满足条件 ϕ ( x i ) y i ( i …

数据结构01 栈及其相关问题讲解【C++实现】

栈是一种线性数据结构&#xff0c;栈的特征是数据的插入和删除只能通过一端来实现&#xff0c;这一端称为“栈顶”&#xff0c;相应的另一端称为“栈底”。 栈及其特点 用一个简单的例子来说&#xff0c;栈就像一个放乒乓球的圆筒&#xff0c;底部是封住的&#xff0c;如果你想…

2024年了,苹果可以通话录音了

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 6月11日凌晨&#xff0c;苹果在WWDC24大会上&#xff0c;密集输出了酝酿多时的AI应用更新。苹果对通话、对话、图…

力扣 SQL题目

185.部门工资前三高的所有员工 公司的主管们感兴趣的是公司每个部门中谁赚的钱最多。一个部门的 高收入者 是指一个员工的工资在该部门的 不同 工资中 排名前三 。 编写解决方案&#xff0c;找出每个部门中 收入高的员工 。 以 任意顺序 返回结果表。 返回结果格式如下所示。 …

Android studio如何导入项目

打开解压好的安装包 找到build.gradle文件 打开查看gradle版本 下载对应的gradle版本Index of /gradle/&#xff08;镜像网站&#xff09; 下载all的对应压缩包 配置gradle的环境变量 新建GRADLE_HOME 将GRADLE_HOME加入到path中 将项目在Android studio中打开进行配置 将gr…

LM339模块电路故障查询

最近的电路测试中出现一个问题&#xff0c;如果不接液晶屏&#xff0c;LM339输入端是高电平&#xff0c;如果接了液晶屏&#xff0c;输入端就是低电平&#xff0c;即使在输入端加了上拉电阻&#xff0c;还是如前面的结论&#xff0c;如果越过LM339,直接和后级电路连接&#xff…

Python爬虫JS逆向进阶课程

这门课程是Python爬虫JS逆向进阶课程&#xff0c;将教授学员如何使用Python爬虫技术和JS逆向技术获取网站数据。学习者将学习如何分析网站的JS代码&#xff0c;破解反爬虫机制&#xff0c;以及如何使用Selenium和PhantomJS等工具进行模拟登录和数据抓取。课程结合实例演练和项目…

ThinkPHP邮件发送配置教程?怎么配置群发?

ThinkPHP邮件发送安全性如何保障&#xff1f;ThinkPHP如何实现&#xff1f; 无论是用户注册后的验证邮件&#xff0c;还是订单处理的通知邮件&#xff0c;都需要一个可靠的邮件发送机制。AokSend将详细介绍如何在ThinkPHP框架中配置邮件发送功能&#xff0c;并带您逐步了解其中…

Python武器库开发-武器库篇之Mongodb未授权漏洞扫描器(五十六)

Python武器库开发-武器库篇之Mongodb未授权漏洞扫描器(五十六) MongoDB 未授权访问漏洞简介以及危害 MongoDB是一款非常受欢迎的开源NoSQL数据库&#xff0c;广泛应用于各种Web应用和移动应用中。然而&#xff0c;由于默认配置的不当或者管理员的疏忽&#xff0c;导致不少Mon…

维度建模中的事实表设计原则

维度建模是一种数据仓库设计方法&#xff0c;其核心是围绕业务过程建立事实表和维度表。事实表主要存储与业务过程相关的度量数据&#xff0c;而维度表则描述这些度量数据的属性。 以下是设计事实表时需要遵循的几个重要原则&#xff0c;来源于《维度建模》那本书上&#xff0…

Dictionary 字典

文章目录 一、什么是字典1.1 字典的创建方式 一、什么是字典 字典&#xff1a; 用来存储数据&#xff0c;与列表和元组不一样的是&#xff0c;字典以键值对的形式对数据进行存储&#xff0c;也就是 key 和 value。相当于 Java 中的 Map。 注意&#xff1a; 1、 key 的值不可重…

[C++][数据结构][AVL树]详细讲解

目录 1.AVL树的概念2.AVL树节点的定义3. AVL树的插入4.AVL树的旋转1.新节点插入较高左子树的左侧 -- 左左&#xff1a;右单旋2.新节点插入较高右子树的右侧 -- 右右&#xff1a;左单旋3.新节点插入较高左子树的右侧 -- 左右&#xff1a;先左单旋再右单旋4.新节点插入较高右子树…

基于System-Verilog点亮LED灯

文章目录 一、System-Verilog介绍1.1System-Verilog 二、简单的语法介绍2.1接口实例2.2全局声明和语句实例2.3时间单位和精度2.4用户定义的类型2.5 枚举类型 三、流水灯参考 一、System-Verilog介绍 1.1System-Verilog SystemVerilog是一种硬件描述和验证语言&#xff08;HDV…

书生·浦语大模型实战营第二期作业五

1、开发机创建conda环境&#xff1a; 2、安装第三方库&#xff1a; 3、新建pipeline_transformer.py文件&#xff0c;并运行&#xff1a; 4、运行结果&#xff1a; 5、执行模型&#xff1a; 6、与大模型进行对话&#xff1a; 7、默认占有的显存&#xff1a; 8、--cache-max-en…

git删除已创建tag标签

前言 一不小心把tag标签名称复制错了&#xff0c;现将删除 1.删除本地标签 1.1.执行下面命令 git tag -d 1.5.2401161.5.240116是创建的tag标签名称 2.如果是删除远程的tag标签名称的话&#xff0c;看下面命令 2.1.删除远程标签 git push --delete origin <tagname>…