《从问题到程序:用Python学编程和计算》——2.7 判断和条件控制

简介:

本节书摘来自华章计算机《从问题到程序:用Python学编程和计算》一书中的第2章,第2.7节,作者 裘宗燕,更多章节内容可以访问云栖社区“华章计算机”公众号查看。

2.7 判断和条件控制

数学里有一些表示判断的算符,如表示数值之间的等于或不等于、大于、小于等。Python提供了一些用于描述条件判断的运算符以及一种特殊的语句(称为if语言,条件语句),它能利用条件判断的结果选择执行不同的语句或语句序列。

2.7.1 条件判断和逻辑表达式

对于数值类型,这里有一组比较运算符用于描述基本条件判断,包括:

image

用一个比较运算符和两个数值表达式,可以构造出一个关系表达式,其意义就是判断两个数值之间的特定关系是否成立。

比较运算符也是一类运算符,求值一个关系表达式,也应该得到一个运算结果。Python用两个特殊的逻辑对象表示比较的结果,它们属于内置的逻辑类型bool,是该类型中仅有的两个对象,关键字True和False分别表示这两个逻辑对象。在做比较时,关系成立就会得到True,表示结果是“真”;关系不成立时将得到False,表示比较的结论是“假”。例如,当20 > 15将得到True,而12 >= 15得到False。

用一个关系运算符可以描述两个数值(表达式)之间的一种关系,但是这往往不够。很多时候我们希望考虑若干关系都成立等一些组合情况。例如,对于三角形的三条边,基本要求是它们的值都大于0,为此就需要写一个组合判断。逻辑研究表明,只需要三个逻辑组合运算,就足以描述所有的组合判断,它们是:

1)A与B,表示A和B都成立的组合判断;

2)A或B,表示A与B之中至少有一个成立的组合判断;

3)非A,表示A不成立的组合判断。

Python为上面三个逻辑组合关系提供了三个运算符:

image

其中,or和and是二元运算符,not是一元运算符。假设A和B是具有逻辑值的表达式(比较表达式或组合逻辑表达式),当且仅当A和B都为真时A and B为真;当且仅当A和B中至少一个为真时A or B为真;当且仅当A为假时not A为真。这三个逻辑组合运算符都是关键字,基于关系和逻辑运算符构造起来的表达式称为逻辑表达式。

例如,3 > 2 and 7 <= 10的值是True,因为3 > 2和7 <= 10都是正确的。not 3 > 2 or 7 > 10 or 7 > 5的值也是True,有关情况请读者自己分析。显然这里也有运算符的优先级和结合性问题。

为方便书写,Python允许连续使用比较运算符。例如x > 1 and x < 10可以简单地写为1 < x < 10。实际上,在Python里还可以写10 < x > y2,表示x > 10 and x > y2。这种形式在数学中不常见。

Python关于比较运算符和逻辑运算符的优先级和结合性的规定如下:

  • 比较运算符的优先级低于算术运算符,因此x + y > x2相当于(x + y) > (x2),是合法的关系表达式。所有比较运算符的优先级相同,连续的比较表示对相邻运算对象做关系运算之后用and连接,相互为“与”关系。
  • 三个逻辑运算符中,一元运算符not的优先级最高,但低于比较运算符,or的优先级最低,and介于两者之间。因此,not x2 > 5 or y < 6 and x y > 8相当于not (x2 > 5) or ((y < 6) and (x y > 8))。

例如,变量a、b、c的值构成一个三角形的三条边,条件可以写为:

a > 0 and b > 0 and c > 0 and \
a + b > c and b + c > a and a + c > b

这里假定了a、b、c的值都是数值。由于表达式很长,这里用了续行符,表示描述的是一个表达式,虽然其正文延续了两行。

2.7.2 if语句(条件语句)

要想根据逻辑判断选择不同的处理方式,就要使用if语句,这种语句也常被称为条件语句或者分支语句。if语句有两种基本形式,其一是:

image

在这个语句执行时,如果表达式为真,就执行语句组中的语句(可以有一个或多个),全部执行完后if语句结束;表达式为假时什么也不做,if语句直接结束。

第二种形式是:

image

如果语句执行时表达式为真,就执行第一个语句组中的语句;表达式为假时执行第二个语句组中的语句。执行完任一个语句组时整个if语句结束。

现在可以重写基于三边长求三角形面积的程序,加进输入检查:

# Program to calculate area of triangle
from math import sqrt

a = float(input("Length of edge a: "))
b = float(input("Length of edge b: "))
c = float(input("Length of edge c: "))

if a > 0 and b > 0 and c > 0 and \
   a + b > c and b + c > a and a + c > b:
    s = (a + b + c) / 2
    area = sqrt(s * (s - a) * (s - b) * (s - c))
    print("Area of the triangle:", area)
else:
    print(a, b, c, "do not form a triangle!")

本程序一次运行的情况如下:

>>> 
Length of edge a: 2
Length of edge b: 5
Length of edge c: 8
2.0 5.0 8.0 do not form a triangle

程序的第一行就是注释,也常被称为注释行。

if语句和程序格式

对一个if语句,从关键字if开始到相应语句组结束称为该语句的if段,从关键字else开始的部分称为其else段(else段可选,可以没有)。其中的“if 表达式:”部分和“else:”部分称为相应段的头部,语句组称为该段的体。

与前面各种简单语句相对应,if这类具有复杂结构(组合结构)的语句被称为复合语句,其中包含一些部分,有些部分本身也是语句。在if语句两个段的语句组里可以出现一个或多个任意的语句,包括if语句本身。这说明if语句的结构具有递归性,其中一些部分可具有与整体相同的结构,整个结构可以任意复杂。如果某语句组里只有一个语句,Python允许把它直接写在该段的头部之后,但人们不倡导这种写法。

为使程序清晰易读,Python语言对if这类组合结构的写法有严格要求,包括两方面:①处于同一层的不同成分必须相互对齐,②下一层的成分需要统一退格。如果一个子部分包含了顺序的多个语句,这些成分语句也必须相互对齐。

以if语句为例,如果它包含else段,if和else两个关键字必须在同一列上对齐(左对齐)。进而,两个语句块里的成分语句需要统一地退格并相互对齐。上面示例程序里的if语句及其成分都正确对齐了,这是必须的。这些要求是Python语言的特殊规定,多数语言没有这种要求。Python采用强制性的格式规定,是为了使程序里的语句结构清晰,具有较好的可读性。

初看起来贯彻上面的规定似乎很麻烦。但如果用IDLE编辑器(或其他专门针对Python的编辑器),保证格式的工作都很简单。IDLE能自动对齐同一层的语句,对于if等组合结构,它也能自动确定内层结构的对齐位置(多增加几个空格,可以自己设置。默认为4个字符,人们认为4个字符既足够清晰,也不带来大片空白,是比较好的设定)。此外,在IDLE编辑状态下按Tab键,IDLE会把输入光标移到下一对齐位置(通过加入几个空格);如果按Backspace键,IDLE就会把输入光标退到前一层对齐位置。做这两种移动时,光标所在的行不变。应特别注意:在编写Python程序时,不要自己用空格键在一行开始加空格,应直接利用IDLE的默认对齐方式,既方便又不会出错。

在编写Python程序时,应特别注意Tab字符和空格不能混用,因为它们都看不见,不易识别。采用非专门用于Python程序的编辑器编程序时,有可能出现这类错误,应该特别注意。程序里出现对齐错误时,解释器也看作语法错,可以定位和报告。

if语句的扩展形式

程序里也经常需要区分多种(两种以上)不同情况,分别处理。显然,这种需求可以用嵌套的if语句表示,即在一个if语句的语句组里再写if语句。Python为常见情况提供了扩展的if语句形式,允许用一系列逻辑表达式来区分多种情况:

image

也就是说,在语句的if段之后可以包含任意多个elif段,每个段包含形式为“elif 表达式:”的头部和一个语句块体。最后是else段。在执行这种if语句时,解释器先求值第一个表达式,如果其值为真就执行第一个语句组,然后整个if结束。如果第一个表达式的值是假,解释器就转去求值随后的elif段头部的表达式,如果其值为真就执行该elif段的语句组,然后整个if结束。如果被求值表达式还是假,解释器就继续考虑下一个elif段,直到在某步求得表达式的值为真,转去执行相应语句组。遇到所有表达式都是假的情况,解释器将执行else段的语句组(如果有这个段)。注意,无论有多少个elif段(及最后的else段),在if语句执行中至多执行一个段里的语句块。

下面将看到这种扩展结构的使用。显然,检查输入只是逻辑判断与条件语句的一种用途,正常计算中也经常需要分情况处理,这时就应该用条件语句。

2.7.3 编程实例

现在考虑几个编程实例。

求二次函数的根

计算二次函数的根是一项很常见的计算:给定二次函数的三个系数,根据公式算出函数的根。这里需要根据判别式的值区分三种情况,可能存在两个实根,或者存在一个重根,或者是无实根(存在一对共轭的复根)。下面只考虑实根的情况。

完成这一计算,应该先求出判别式的值,然后根据这个值分情况处理。根据二次函数的求根公式,不难写出下面的程序:

from math import sqrt

print("Program for root(s) of quadratic equetions.")
a = float(input("Coefficient of x**2: "))
b = float(input("Coefficient of x: "))
c = float(input("Constant: "))

d = b**2 - 4 * a * c
if d > 0:
    tmp = sqrt(d)
    print("Two roots:", (-b + tmp)/2/a,  (-b - tmp)/2/a)
elif d == 0:
    print("One root:", -b/2/a)
else:
    print("No real root")

这里增加了第一个打印语句,告知用户这是什么程序,是一种提示。程序里使用了扩展的if语句,分三种情况分别处理。还需要注意的是除以2a的写法。

读者在前面已经看了不少程序执行情况。为了减少页面占用,今后除一些特殊情况外,书中将不再给出程序执行的情况。请读者自己运行程序查看效果。

简单总计

买一种货品需要从单价和数量算出总货款。考虑写一个程序完成这一简单计算。显然,计算中也需要输入数据。不难写出下面程序,其中做了必要的检查:

# A program calculating total price of some goods

name = input("Please give the name of the good: ")
price = float(input("Price of one piece of the good: "))
amount = int(input("Amount: "))

if price > 0 and amount > 0:
    print(amount, "pieces of", name, 
          "totally: ", price * amount)
else:
    print("Error. Price and amount should be positive.")

在这个程序里可以看到字符串的使用,以及如何结合使用字符串(字面量和保存在变量的字符串)和数值,生成较为复杂的输出形式。

当然,也可以利用字符串操作生成出同样的字符串,令print输出构造好的串。如果只是为了产生输出,仅利用print输出多个参数值的功能就能满足需要,像上面这样直接输出可能更方便。作为练习,请读者修改程序,利用字符串操作构造出同样的或更符合自己想法的字符串,而后调用print输出该串。

相关文章
|
12天前
|
安全 Java 数据处理
Python网络编程基础(Socket编程)多线程/多进程服务器编程
【4月更文挑战第11天】在网络编程中,随着客户端数量的增加,服务器的处理能力成为了一个重要的考量因素。为了处理多个客户端的并发请求,我们通常需要采用多线程或多进程的方式。在本章中,我们将探讨多线程/多进程服务器编程的概念,并通过一个多线程服务器的示例来演示其实现。
|
12天前
|
程序员 开发者 Python
Python网络编程基础(Socket编程) 错误处理和异常处理的最佳实践
【4月更文挑战第11天】在网络编程中,错误处理和异常管理不仅是为了程序的健壮性,也是为了提供清晰的用户反馈以及优雅的故障恢复。在前面的章节中,我们讨论了如何使用`try-except`语句来处理网络错误。现在,我们将深入探讨错误处理和异常处理的最佳实践。
|
16天前
|
缓存 监控 Python
解密Python中的装饰器:优雅而强大的编程利器
Python中的装饰器是一种强大而又优雅的编程工具,它能够在不改变原有代码结构的情况下,为函数或类添加新的功能和行为。本文将深入解析Python装饰器的原理、用法和实际应用,帮助读者更好地理解和利用这一技术,提升代码的可维护性和可扩展性。
|
4天前
|
数据采集 JavaScript 前端开发
使用Python打造爬虫程序之破茧而出:Python爬虫遭遇反爬虫机制及应对策略
【4月更文挑战第19天】本文探讨了Python爬虫应对反爬虫机制的策略。常见的反爬虫机制包括User-Agent检测、IP限制、动态加载内容、验证码验证和Cookie跟踪。应对策略包括设置合理User-Agent、使用代理IP、处理动态加载内容、验证码识别及维护Cookie。此外,还提到高级策略如降低请求频率、模拟人类行为、分布式爬虫和学习网站规则。开发者需不断学习新策略,同时遵守规则和法律法规,确保爬虫的稳定性和合法性。
|
5天前
|
安全 数据处理 开发者
《Python 简易速速上手小册》第7章:高级 Python 编程(2024 最新版)
《Python 简易速速上手小册》第7章:高级 Python 编程(2024 最新版)
18 1
|
5天前
|
人工智能 数据挖掘 程序员
《Python 简易速速上手小册》第1章:Python 编程入门(2024 最新版)
《Python 简易速速上手小册》第1章:Python 编程入门(2024 最新版)
34 0
|
5天前
|
SQL 安全 Go
如何在 Python 中进行 Web 应用程序的安全性管理,例如防止 SQL 注入?
在Python Web开发中,确保应用安全至关重要,主要防范SQL注入、XSS和CSRF攻击。措施包括:使用参数化查询或ORM防止SQL注入;过滤与转义用户输入抵御XSS;添加CSRF令牌抵挡CSRF;启用HTTPS保障数据传输安全;实现强身份验证和授权系统;智能处理错误信息;定期更新及审计以修复漏洞;严格输入验证;并培训开发者提升安全意识。持续关注和改进是保证安全的关键。
12 0
|
6天前
|
Python Serverless API
Python风险价值计算投资组合VaR、期望损失ES
Python风险价值计算投资组合VaR、期望损失ES
23 0
Python风险价值计算投资组合VaR、期望损失ES
|
6天前
|
API Python
Python模块化编程:面试题深度解析
【4月更文挑战第14天】了解Python模块化编程对于构建大型项目至关重要,它涉及代码组织、复用和维护。本文深入探讨了模块、包、导入机制、命名空间和作用域等基础概念,并列举了面试中常见的模块导入混乱、不适当星号导入等问题,强调了避免循环依赖、合理使用`__init__.py`以及理解模块作用域的重要性。掌握这些知识将有助于在面试中自信应对模块化编程的相关挑战。
19 0
|
6天前
|
Python
Python金融应用编程:衍生品定价和套期保值的随机过程
Python金融应用编程:衍生品定价和套期保值的随机过程
14 0