🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # 第3章 分支结构 # [插画:下述场景] 在前面的学习中,小墨编写的程序都是顺序结构的,今天,他将遇到一种新的程序结构:分支结构。除此之外他还遇到了布尔类型、关系表达式、逻辑运算符等内容,这些内容虽然很有意思,但是也充满了陷阱,他会如何避免呢?最后,墨博士要求他必须做完三道练习才能回家,一起来看看他是怎么解决的吧。 时间:早上9:05 场景:墨馨书屋门外走廊里 小墨匆匆的跑过来... 墨博士:早上好,小墨 小墨:不好意思!今天早上我跟往常一样起床,出门的时候发现下着雨就带了把雨伞,走到半路风太大了,把我伞都吹坏了,我只好去找了家商店重新买了把,结果就迟到了。 墨博士:没关系的,快进来吧。 小墨:博士,今天我们学习什么呢? 墨博士:今天来学习分支结构:前面我们编写的程序都是从上到下顺序执行的,比如有3行代码,程序就会先执行第1行,再执行第2行,然后是第3行,然后程序运行结束。而程序是对现实世界的模拟,现实世界中的事情可不都是“顺序执行”的,比如你早起出门,会根据天气选择带不带雨伞,雨伞坏了会去重新买一把,甚至可以说,你每天都会经历无数的选择。这种选择,在程序中称为**分支结构**。 好了,让我们开始吧。 ## 3.1 关系运算符 首先先来做一个练习: > 编写一个程序,能够输入你的python考试成绩,如果成绩小于60,则输出“成绩不及格”。 小墨:嗯,我想想,先定义一个变量,接收输入的成绩 ``` score = input('请输入你的Python成绩:') ``` 墨博士:嗯,不错。然后呢? 小墨:然后判断这个输入的成绩和60的关系,小于60的话就使用print语句输出成绩不及格。判断成绩和60的关系在数学上是使用大于、小于,不知道这个在Python中如何表示。 墨博士:思路很清晰。Python中的大于、小于和数学上的一样,如果成绩变量是score,那么表示成绩小于60使用“score < 60”就可以了。 在编程语言中,操作一个以上数据进行运算的符号,称为**运算符**,比如1+2中的+号,是算术运算符。a=2中的=号,是赋值运算符。&gt;和<也是运算符,称为关系运算符。由运算符和操作数组成的式子称为表达式,比如1+2称为算术表达式、a=2称为赋值表达式,score<60称为关系表达式等。 > 墨博士提醒:Python中完整的运算符及使用方法请参考附录B。 python中的关系运算符一共有6个,如表3.1所示。 表3.1 python中的关系运算符 | 关系 | 符号 | |:-:|:-:| | 大于 | > | | 小于 | < | | 等于 | == | | 大于等于 | &gt;= | | 小于等于 | <= | | 不等于 | != | 小墨:这个等于是使用两个等号吗? 墨博士:还记得我们前面说过的赋值吗,在Python中一个等号“=”表示赋值。因为赋值已经把一个等号“=”给占上了,Python中判断是否等于就用了两个等号“==”。 小墨:哦,原来是这样,我记住了。那这个score > 60如何来用呢? 墨博士:不要着急,我们先来了解一个新的数据类型:布尔类型。 ## 3.2 布尔类型 墨博士:以“score<60”为例,这里的score是个变量,表示真正的分数值可以变化,比如score可以是99,也可以是10,可以是任意一个数值,那么“score<60”就只会得到两种结果: 1. 如果score本身大于等于60,那么“score<60”表达式不成立 2. 而如果score本身就是小于60的一个数,那么“score<60”表达式成立 这个成立还是不成立在程序中如何表示呢?看下面这段代码: ``` score = 65 print(score < 60) score = 55 print(score < 60) ``` 运行,结果为: ``` False True ``` 这里的False和True就用来表示score<60是否成立,其中False表示不成立,True表示成立。 从数据类型上来说,这里的True和False,不同于1、2这种整数,也不同于'abc'这种字符串,这是一种新的数据类型,称为布尔(bool、boolean)类型。关系表达式的运算结果就是布尔类型。 小墨:布尔,听起来是个厉害的角色。 墨博士:布尔是19世纪英国的一个伟大数学家的名字,计算机中的逻辑运算称为布尔运算,计算机中的True和False称为布尔值。 ![](https://img.kancloud.cn/f9/f9/f9f942f60c92b5135125f9c1b5923bb9_268x326.png) > 墨博士提醒:如果是写完整的程序,可以通过IDLE启动Python编辑器然后在编辑器中编写代码,如果只是想测试下某个知识点,通过IDLE本身就可以了。这里我们测试下布尔类型,如下: ``` >>> a = True >>> print(a) True >>> b = False >>> print(b) False ``` 小墨:博士你懂的真多,不过你又啰嗦了,说了这么多,还是没解决最初的练习题呢。 墨博士:下面我们就一起来解决一下吧。 ## 3.3 if 墨博士:在python中,条件判断的情况使用if去处理,语法为: ``` if 条件: 语句 ``` 注意条件后面跟的是英文的冒号,Python中所有的符号都是英文的;第二行语句前是四个空格。Python为了代码的简洁和优美,采用一个Tab或四个空格作为缩进,表示一种所属关系。上面代码就表示如果条件成立,则执行语句,如果不成立,则不执行语句。 小墨:一个Tab键和四个空格是一样的吗? 墨博士:虽然一个Tab键或四个空格都可以用来缩进,但是还是建议你使用四个空格。在IDLE中默认也是四个空格,如图3.1所示。 ![图像说明文字](http://p7moyixbi.bkt.clouddn.com/%E5%9B%BE3.1.png) {-:-}图3.1 IDLE中默认四个空格作为缩进方案 在IDLE中写完if语句后,敲下回车,光标也会自动定位在缩进4个空格处。 接下来我们用if语句把你上述的练习代码补充完整: ``` score = int(input("请输入你的python考试成绩:")) # 如果成绩小于60分 if score < 60: print('成绩不及格') # 注意这句前面的4个空格 ``` 运行,结果为: ``` 请输入你的python考试成绩:48 成绩不及格 ``` 看,我们就把练习的场景模拟出来了。 注意程序中的第1行,用户输入成绩,用score变量接收,由于**input输入默认是字符串类型**,这里要外面包一层int(),将字符串转为int整数类型。第2行以#号开头的,称为程序中的**注释**。所谓注释,就是针对代码的解释说明,它可能是留着自己看,可能是给一块写代码的队友看,总之呢是给人看的(代码是给计算机看的),运行的时候计算机会忽略它。在Python中,单行注释的写法就是#开头,到这一行的末尾结束,一般#号后面会留个空格。单行注释可以加上要注释的内容的上面,也可以加在要注释的内容的后面。 小墨:好的,我已经记住了。 ## 3.4 if-else 墨博士:小墨,现在我们来把问题复杂一点: > 请输入您的python考试成绩,如果成绩小于60,则输出“成绩不及格”,反之则输出“恭喜及格”。 该如何做呢? 小墨:我知道我知道! ``` score = int(input("请输入你的python考试成绩:")) # 如果成绩小于60分 if score < 60: print('成绩不及格') if score >= 60: print('恭喜及格') ``` 墨博士:嗯。这确实是一种办法。除此之外,Python还提供给我们了一种方法,就是if-else结构: ``` if 条件: 执行代码1 else: 执行代码2 ``` else表示剩下的、其他的、否则,也即不符合if条件的。它的执行顺序是,如果条件1成立,则执行代码块1,否则,执行代码块2。 小墨:哦,这个好这个好,我写的程序需要判断两次,这个if-else结构只需要进行一次判断就可以了。 墨博士:嗯。上面的问题代码实现如下: ``` # 接收用户输入的成绩 score = int(input("请输入你的python考试成绩:")) # 如果成绩小于60 if score < 60: print('不及格') # 打印不及格 # else否则,也即对成绩小于60取反,那就是大于等于60分,就是及格 else: print('恭喜及格') ``` ## 3.5、if-elif-else 墨博士:小墨,现在我们继续升级难度: > 请输入你的python考试成绩,如果成绩大于80,则输出“优秀”,如果小于等于80但大于等于60,则输出“及格”,如果小于60分则输出“不及格”。 这个如何做呢? 小墨:博士,你先别讲,我猜一下:Python提供了处理两个分支的if-else,那估计也提供的有处理多个分支的情况。 墨博士:是的,如果程序有多个分支,则使用if-elif-else结构,如下: ``` if 条件1: 执行代码块1 elif 条件2: 执行代码块2 else: 执行代码块3 ``` elif是else if的缩写,后面也是跟条件,表示在前面if条件不满足的里面挑选符合后跟条件的。 上述if-elif-else结构的执行流程为:如果条件1成立,则执行代码块1,如果条件1不成立,则往下走,**在不符合条件1的成绩里面**判断条件2,如果条件2成立,则执行代码块2,如果条件2也不成立,则执行else下的语句块3。 使用if-elif-else完成上述练习,代码如下: ``` score = int(input("请输入您的python考试成绩:")) if score > 80: print('优秀') # 这里的elif,表示if条件不符合的情况,也即取score小于等于80的, # 然后在这个小于等于80的成绩中再判断是否大于等于60 elif score >= 60: print('及格') else: print('不及格') ``` 小墨:博士,我懂了。并且我已经懂得你的套路了。咳咳,墨博士同学,听好了,下面我们再把问题复杂一下,请输入你的python考试成绩,如果成绩大于等于90,则输出“优秀”,如果小于90但大于等于70,则输出“良好”,如果小于70但大于等于60,输出“一般”,而如果小于60分则输出“不及格”。这个如何做呢? 墨博士:... 小墨:这个依然使用if-elif-else实现,如下: ``` score = int(input("请输入您的python考试成绩:")) if score >= 90: print('优秀') # 这里的elif,是在不符合score >= 90的情况下再判断是否大于等于70 # 也即在score<90的情况下判断是否大于等于70 # 符合题目中如果小于90但大于等于70的要求 elif score >= 70: print('良好') # 这个elif,是在不符合条件score>=90,也不符合score>=70的条件下 # 取score>=60,也即取小于70大于等于60的范围 elif score >= 60: print('一般') # 这个else是上述三个条件都不成立,也即小于60的情况 else: print('不及格') ``` 墨博士:做的不错!既然你已经掌握了,那我们就来总结一下吧。 上面4个案例就是if语句的全部用法了,总结一下,在if语句中: * if语句、elif语句后跟条件,当条件满足时执行对应语句块 * 如果所有条件都不满足,则执行else语句块 * if可以单独使用,elif和else不能单独使用 * if出现1次,elif可以出现0-多次,而else可以出现0-1次 ## 3.6 if语句使用注意事项 墨博士:小墨,if语句语法简单,也非常常用,后面的几乎每个程序中你都可以看到它的身影。你现在已经掌握了它的基本用法,但还是需要注意下if语句使用时的一些问题。 小墨:嗯,if语句使用时都需要注意哪些问题呢? ### 3.6.1 缩进问题 墨博士:上面我们提到,python中使用缩进表示从属关系,以为了让代码更简洁,比如下面的代码: ```{} score = 80 if score < 60: print('不及格') print('1') ``` 输出结果为1 而 ```{} score = 80 if score < 60: print('不及格') print('1') ``` 则什么都不会输出。原因是第二个程序中的第3和4两行都有缩进,它们组成了一个整体(多行代码一起,称为代码块),都属于if条件的覆盖范围。 而第一个程序中的print('1')这句,由于没有缩进,和前面if就不是从属关系,而是并列关系,是新的一行,所以不受if的影响。 小墨:缩进与否还影响着代码的逻辑,这确实是一个值得注意的问题! ### 3.6.2 变量作用范围问题 墨博士:另一个需要注意的问题跟上面的问题有关,修改上述代码为: ``` score = 50 if score < 60: s = '不及格' print(s) ``` 运行输出“不及格”,而如果改成这样: ``` score = 50 if score < 60: s = '不及格' print(s) ``` 运行仍然输出“不及格”。 也就是说:if覆盖范围内定义的变量,在if覆盖范围外仍然可以访问。 小墨:这个问题我也记住了。 墨博士:好,我们继续。小墨同学,既然你已经知道了我的套路,那么现在我就再次将练习难度升级: 现在有python和数学两科成绩,请根据以下评分标准给出成绩的等级。 * 1、python90(含)-100分 并且数学 90(含)-100分 输出:优秀 * 2、python或数学中有一科90分(含)及以上,但是另一科60分以下 输出:偏科 该如何来做呢? ## 3.7 逻辑运算符 小墨:博士,这个还是你来说吧。 墨博士:这个问题我们可以通过if分支结构的嵌套来解决。小墨你听过伪代码吗? 小墨:没有诶。 墨博士:所谓伪代码就是表达思路但是不能运行的代码,来看一个if嵌套的案例的伪代码: ``` if 你英语考了100分: if 你是中国人: 则说明你外语很好 elif 你是美国人: 则说明你母语很好 ``` 可以看到英语考了100分是大前提,在此大前提下又区分了你是中国人还是美国人,如果你是中国人,就说明你外语学的不错,如果你是美国人,则说明你母语很好。 小墨:嗯我理解了,if里面还有if,某种情况下又细分了某些情况。 墨博士:是的,这就是if嵌套的思路。理解了这个伪代码之后,我们尝试着解决下上面的练习,代码如下: ```{} # 定义python的分数 p_score = 58 # 定义数学的分数 m_score = 98 if p_score >= 90: # 如果python分数大于等于90 if m_score >= 90: print('优秀') elif m_score < 60: print('偏科') elif p_score < 60: if m_score >= 90: print('偏科') ``` 程序的第5行if p_score >= 90表示在python成绩大于等于90的基础上,执行后面跟的代码块(第6-9行)。 第6-9行又是一个新的if结构,第6行表示如果数学成绩m_score大于等于90,则执行第7行。因为现在的大环境就是python成绩大于等于90,而这里数学成绩如果也满足了大于等于90的条件,当然输出优秀了。 小墨:哦,明白了。同样的第10行表示python成绩小于60的大环境,如果此时数学成绩又大于等于了90分,则说明这位同学偏科。数学好但是python差。 墨博士:是的。除了使用if分支结构的嵌套外,你还可以使用逻辑运算符来解决该问题。 小墨:什么是逻辑运算符呢? 墨博士:逻辑运算符有三种:与、或、非,表示逻辑上的同时成立、一方成立、不成立关系。我们之前曾说过,程序是对现实世界的抽象和模拟,程序中的东西都可以在现实生活中找到原型。下面的句子都是生活中常见的“逻辑”的使用场景: * 如果你英语考了100分,**并且**你是中国人,则说明你外语很好; * 明天太热**或**太冷,我都不会出门; * 如果你成绩**不**好,那你要加油了。 小墨,你能用逻辑词来举个例子吗? 小墨:如果爸爸明天**不**上班,他就会带我去科技馆**或**图书馆。 墨博士:不错的例子。回到Python中,逻辑运算符与、或和非对应的符号为:and(与)、or(或)和not(非) and的用法如下: ``` a = 2 b = 2 print(a > 0 and b > 0) print(a < 0 and b < 0) print(a > 0 and b < 0) print(a < 0 and b > 0) ``` 运行,输出结果为: ``` True False False False ``` 小墨,你发现什么规律了吗? 小墨:嗯……, * 如果and运算的两边都为True,则运算结果为True * 如果and运算的其中一边为False,则运算结果就为False 是这样的吧博士。 墨博士:是的。再来看or的用法,如下: ``` a = 2 b = 2 print(a > 0 or b > 0) print(a < 0 or b < 0) print(a > 0 or b < 0) print(a < 0 or b > 0) ``` 运行输出结果为: ``` True False True True ``` 聪明的小墨,这次的规律又是什么呢? 小墨:规律是: * 如果or的两边有一边为True,其运算结果就为True * 如果两边都是False,则运算结果是False 没说错吧。 墨博士:没错。最后再来看下not的用法: ``` a = 2 print(not a > 0) print(not a < 0) ``` 运行结果为: ``` False True ``` 小墨,还是你来总结下规律吧。 小墨:not True为False,not False为True。不真就是假,不假就是真。 墨博士:是的,逻辑运算符的计算就这么多了。现在我们用逻辑运算符来解决下前面的练习吧。 代码如下: ``` p_score = 58 m_score = 98 if p_score >= 90 and m_score >= 90: print('优秀') elif p_score >= 90 and m_score < 60 or p_score < 60 and m_score >= 90: print('偏科') ``` 小墨:厉害!这种写法比if的嵌套简短了不少,逻辑也清晰了很多。 墨博士:这三种逻辑运算符单独或组合使用,就能解决大部分的逻辑问题,所以有必要好好掌握哦。 ## 3.8 逻辑运算符陷阱 墨博士:小墨,逻辑运算符中也有一个陷阱,还是来看一个练习:已知有4个人a,b,c,d,现在4个人进行投票表决一件事情,已知a同意并且b,c,d三人其中一个同意就表示同意这件事,你来补充以下下面的if条件,用于模拟这种同意的条件: ``` a = True b = True c = False d = False if ____: print("同意") ``` 答案是什么呢? 小墨:这个……,应该填上“a and b or c or d”吧,你看,程序运行确实输出了同意。 墨博士:那如果我们把代码再改以下,你再运行试试: ``` a = False b = False c = True d = False if a and b or c or d: print("同意") ``` 小墨:咦……怎么回事,运行依然是同意。这个a=False已经说明a不同意了。 墨博士:这显然有逻辑问题了。问题的原因是运算符的优先级问题,就像如下代码: ``` >>> print(1 + 2 * 3) 7 ``` 运行之所以输出7而不是9的原因就在于1+2*3先计算了2乘以3,结果为6,然后计算了1+6,结果为7。也就是说,乘号*的优先级是比加号+的优先级高的,优先级改变了表达式的运算顺序。 > 墨博士提醒:完整的运算符的优先级介绍请参见附录B 同样,在Python中or运算优先级并不比and高,所以上述a and b or c or d会顺序执行:a先和b用and计算,计算的结果再和c进行or运算,计算的结果再和d进行or运算。针对本题的情况,就出现逻辑问题了。 正确的逻辑应该是a作为一个整体,b or c or d作为一个整体,两者进行and运算。这使用一个小括号提示下优先级就行了,修改后的代码如下: ``` a = True b = False c = True d = False if a and (b or c or d): print("同意") ``` 小墨:哦,我明白了。 ## 3.9 本章小结 墨博士总结:好了,分支结构的内容学到这里就结束了。我来总结一下今天的主要内容: 1、分支结构的完整用法是if-elif-elif-elif-else 2、布尔类型:True和False 3、运算符,尤其是逻辑运算符和关系运算符的使用。关系运算符运算的结果是布尔类型,逻辑运算符运算的结果也是。 4、另外还有一个,昨天我们学习了str()能将整数转为字符串,今天学习了int()能将字符串转为整数。 这些内容都很简单,但是这些是后面的基础,要能够熟练使用。 另外小墨同学,你今天的表现非常棒,值得鼓励。但是你今天要做的还没有结束。编程的核心是编,只有不断的动手去编、大胆的去试,你才能真正的掌握这项技能。下面三个练习,来挑战一下吧。 ## 3.10 小墨的练习题 下面是博士给小墨留的三个练习,其中第三题还附带了一个小提示: 练习一:三角形的构成条件是:任意两边之和大于第三边。请编写程序,定义变量a、b和c表示三角形的三条边长,判断这三条边长能够构成三角形。 练习二:录入三个正整数,判断最大的数是多少,并指出第几个数最大。 练习三:输入年份、月份和日期,输出该日期是今年的第几天。需要考虑闰年问题。其中闰年的判断条件是: 1、能整除4且不能整除100 2、能整除400 也就是四年一闰,百年不闰,四百年再闰。 小提示:在Python中如何表示能整除4呢?对4取余,判断结果是否等于0就可以了。代码为: ``` year % 4 == 0 ``` 其中的%就是Python中的取余运算符(Python中完整的运算符请参考**附录B**)。 # [插画:地球绕太阳转,闰年相关] > 闰年产生的原因:地球绕太阳运行周期为365天5小时48分46秒(合365.24219天)即一回归年(tropical year)。公历的平年只有365日,比回归年短约0.2422 日,所余下的时间约为每四年累计一天,故第四年于2月末加1天,使当年的历年长度为366日,这一年就为闰年。现行公历中每400年有97个闰年。按照每四年一个闰年计算,平均每年就要多算出0.0078天,这样经过四百年就会多算出大约3天来。因此每四百年中要减少三个闰年。所以公历规定:年份是整百数时,必须是400的倍数才是闰年;不是400的倍数的世纪年,即使是4的倍数也不是闰年。 以下是小墨同学针对三个练习的答案。 练习一小墨的答案: ``` # 定义a、b和c表示三条边 a = 2 b = 5 c = 9 # 三角形的判断条件 if a + b > c and a + c > b and b + c > a: print('是三角形') else: print('不是三角形') ``` 练习二小墨的答案: ``` # 定义三个变量接收用户的输入 a = int(input('输入第一个数:')) b = int(input('输入第一个数:')) c = int(input('输入第一个数:')) # 定义变量max_num,表示最大值 max_num = -1 # 定义第几个数是最大值 max_index = 0 # 如果a比最大值max_num大,则将a作为最大值 if max_num < a: max_num = a max_index = 1 # 如果b比max_num大,则将b作为最大值,此时max_num是a和b中最大的那个 if max_num < b: max_num = b max_index = 2 # 如果c比max_num大,则将c作为最大值,此时max_num是a、b和c中最大的那个 if max_num < c: max_num = c max_index = 3 print('第%s个数最大,最大值为:%s' % (max_index, max_num)) ``` 运行结果为: ``` 输入第一个数:5 输入第一个数:4 输入第一个数:8 第3个数最大,最大值为:8 ``` 练习三小墨的答案: ``` # 定义year、month和day表示输入的年、月和日 year = int(input('请输入年份:')) month = int(input('请输入月份:')) day = int(input('请输入日期:')) # 定义变量february_days,赋值为28 february_days = 28 if year % 4 == 0 and year % 100 != 0 or year % 400 == 0: # 如果符合闰年的条件,则将february_days更改为29 february_days = 29 # 定义变量days,用来表示这是一年中的第几天 days = 0 # 如果月份是1,则输入的日期就是今年中的第几天,比如1月10日,就是一年中的第10天 if month == 1: days += day # 如果月份是2,则输入的日期加上第一个月的31天就是一年中的第几天 elif month == 2: days = 31 + day # 如果月份是3,则输入的日期加上第一个月的31天,以及第二个月的天数february_days(可能28,可能29,上面已经计算好) # 就是一年中的第几天,其他月份依次类推 elif month == 3: days = 31 + february_days + day elif month == 4: days = 31 + february_days + 31 + day elif month == 5: days = 31 + february_days + 31 + 30 + day elif month == 6: days = 31 + february_days + 31 + 30 + 31 + day elif month == 7: days = 31 + february_days + 31 + 30 + 31 + 30 + day elif month == 8: days = 31 + february_days + 31 + 30 + 31 + 30 + 31 + day elif month == 9: days = 31 + february_days + 31 + 30 + 31 + 30 + 31 + 31 + day elif month == 10: days = 31 + february_days + 31 + 30 + 31 + 30 + 31 + 31 + 30 + day elif month == 11: days = 31 + february_days + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + day elif month == 12: days = 31 + february_days + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + day # 拼接结果后输出 print('%s年%s月%s日是今年的第%s天' % (year, month, day, days)) ``` 运行结果为: ``` 请输入年份:2018 请输入月份:12 请输入日期:31 2018年12月31日是今年的第365天 ``` 小读者们,这些练习你有更好的解决办法吗?快来和小墨比比吧。