Python每日一学 05——布尔运算

Python每日一学 05——布尔运算

一、布尔运算

布尔运算也称为逻辑运算,包括“and(与)”、“or(或)”、“not(非)”运算。

运算符表达式功能描述
orx or y首先对表达式 x 求值,如果值为True则返回 x的值,否则对表达式y求值并返回其结果值。
andx and y首先对表达式 x 求值,如果值为False则返回 x的值,否则对表达式y求值并返回其结果值。
notnot x表达式 x 值为 False时返回 True,否则返回 False。

注释:

or与and都是短路运算符,因此只有在第一个参数为假值时才会对第二个参数求值。not 的优先级比非布尔运算符低,因此 not a == b 会被解读为 not (a == b) 而 a == not b 会引发语法错误。

请注意 and 和 or 都不限制其返回的值和类型必须为 False 和 True,而是返回最后被求值的操作数, not 则不论其参数为何种类型它都会返回一个布尔值。

print(10 and 'hello')        # 输出 hello,非空字符串,布尔值为True
print(bool(10 and 'hello'))  # hello,非空字符串,布尔值为True
hello
True
print(10 or 'hello')         # 输出整数 10,非0,布尔值为True
print(bool(10 or 'hello'))   #  10,非0,布尔值为True
10
True
print(10 or '')              # 输出整数 10,非0,布尔值为True
print(bool(10 or ''))        # 整数 10,非0,布尔值为True

10
True
print(10 and '')             # 输出'',空字符串,布尔值为False
print(bool(10 and ''))       # '',空字符串,布尔值为False
False

逻辑运算 or 和 and 的值是参与运算的表达式的值之一,not 运算结果一定是布尔值,值为True或False

print(not 10)       # 10是非0整数,布尔值为True,取非结果为False
print(not '')       # '',空字符串,布尔值为False,取非结果为True
False
True

布尔运算可放到 ifwhile 后面的条件表达式中,根据真值测试的结果决定是否执行分支下的语句。

if 10 and '':     # 10 and ''布尔运算的值是空字符串,条件运算结果为False
    print(True)   # 当10 and ''布尔运算值是True时,输出True
else:             # 否则
    print(False)  # 输出 False,执行此分支
False

上述分支语句的程序可以用下面一行代码实现:

print(bool(10 and ''))
False

布尔运算可放到赋值语句中,将布尔运算的结果赋值给前面的变量。下述语句中,若input()函数接收到非空输入时,值为True,将接收到的字符串赋值给变量;若直接回车,接收到空字符串,此时布尔运算的值为or右侧的“保密”,将“保密”赋值给左侧的变量。

birthdate = input('请输入出生日期: ') or '保密'
print(birthdate)                    # 无输入,直接回车时,输出'保密'
请输入出生日期: 
保密

解释器先对逻辑运算符左侧的操作数进行运算这种特性称为短路特性。当布尔运算符左侧的表达式已经可以决定布尔运算的结果时,该语句之后的所有代码都不会被执行。短路特性可以有效的提高效率。把容易判断、计算量较小的表达式放在逻辑运算符的左侧,可以减少不必要的运算,提高算法效率。

二、实例:输出20000以内的所有回文素数

判断一个数是否是回文素数时,将判断回文表达式str(i) == str(i)[::-1]放在运算符左侧,当判断不是回文时,不再执行右侧判定素数函数prime(i)。因为判定素数的计算量较大,这样设计可以极大的降低运算量,提高效率。断回文素数的完整程序如下(后续章节将详细讲解,这里不讲函数,只让大家了解计算量大的放到逻辑运算符右侧会极大提高效率)

import datetime # 导入datetime,用于计算程序运行时间


def prime(n):
    """接收正整数n,判断是否为素数,返回布尔值"""
    if n < 2:
        return False       # 0和1不是素数
    for i in range(2, n):  # 遍历(2, n-1)中的数
        if n % i == 0:     # 若在(2, n-1)中存在因子则不是素数
            return False   # 不是素数时返回False
    else:   # for语句遍历(2, n-1)中所有数,未发现因子存在时,才是素数
        return True        # 素数时返回True

    
start = datetime.datetime.now()  # 记录程序开始时间

for i in range(20000):
    # 利用短路提高效率
    if prime(i) and str(i) == str(i)[::-1]: # 先判断素数,再判断回文,效率低
        print(i,end=' ')
        
end = datetime.datetime.now()  # 记录程序结束时间
during = (end - start).seconds * 1000 + (end - start).microseconds / 1000  # 计算耗时,精确到毫秒 
print(f'\n耗时:{during}毫秒')
2 3 5 7 11 101 131 151 181 191 313 353 373 383 727 757 787 797 919 929 10301 10501 10601 11311 11411 12421 12721 12821 13331 13831 13931 14341 14741 15451 15551 16061 16361 16561 16661 17471 17971 18181 18481 19391 19891 19991 
耗时:1456.962毫秒
import datetime # 导入datetime,用于计算程序运行时间


def prime(n):
    """接收正整数n,判断是否为素数,返回布尔值"""
    if n < 2:
        return False       # 0和1不是素数
    for i in range(2, n):  # 遍历(2, n-1)中的数
        if n % i == 0:     # 若在(2, n-1)中存在因子则不是素数
            return False   # 不是素数时返回False
    else:   # for语句遍历(2, n-1)中所有数,未发现因子存在时,才是素数
        return True        # 素数时返回True

    
start = datetime.datetime.now()  # 记录程序开始时间

for i in range(20000):
    # 利用短路提高效率
    if str(i) == str(i)[::-1] and prime(i): # 先判断回文,再判断素数,效率高
        print(i,end=' ')
        
end = datetime.datetime.now()  # 记录程序结束时间
during = (end - start).seconds * 1000 + (end - start).microseconds / 1000   # 计算耗时,精确到毫秒 
print(f'\n耗时:{during}毫秒')
2 3 5 7 11 101 131 151 181 191 313 353 373 383 727 757 787 797 919 929 10301 10501 10601 11311 11411 12421 12721 12821 13331 13831 13931 14341 14741 15451 15551 16061 16361 16561 16661 17471 17971 18181 18481 19391 19891 19991 
耗时:42.089毫秒

三、实例:判断输入的年份是否为闰年

用户输入一个年份,若该年份为闰年,则输出’XXXX年是闰年’;否则输出’XXXX年不是闰年’。

公历闰年判定遵循的规律为:“四年一闰,百年不闰,四百年再闰。”,符合以下条件之一的年份即为闰年

  1. 能被4整除而不能被100整除。
  2. 能被400整除。

输入输出样例:

输入:2000
输出:2000年是闰年

输入:2022
输出:2022年不是闰年
year = int(input())  # 输入整数年份
# 参考前例,根据条件使用if...else...判断是否为闰年,并输出对应信息
if (year%4==0) and (year%100 !=0) or (year%400)==0:
    print("{}年是闰年".format(year))
else:
    print("{}年不是闰年".format(year))
2022
2022年不是闰年

改变逻辑运算的顺序,参考回文素数的例子,计算运算时间,考察不同运算顺序是否影响效率?

# 补充你的代码

import datetime # 导入datetime,用于计算程序运行时间

start = datetime.datetime.now()  # 记录程序开始时间

if (year%4==0) and (year%100 !=0) or (year%400)==0:
    print("{}年是闰年".format(year))
else:
    print("{}年不是闰年".format(year))
        
end = datetime.datetime.now()  # 记录程序结束时间
during = (end - start).seconds * 1000 + (end - start).microseconds / 1000   # 计算耗时,精确到毫秒 
print(f'\n耗时:{during}毫秒')

2022年不是闰年

耗时:0.166毫秒
import datetime # 导入datetime,用于计算程序运行时间

start = datetime.datetime.now()  # 记录程序开始时间

if (year%100 !=0) and (year%4==0) or (year%400)==0:
    print("{}年是闰年".format(year))
else:
    print("{}年不是闰年".format(year))
        
end = datetime.datetime.now()  # 记录程序结束时间
during = (end - start).seconds * 1000 + (end - start).microseconds / 1000   # 计算耗时,精确到毫秒 
print(f'\n耗时:{during}毫秒')
2022年不是闰年

耗时:0.237毫秒

逻辑运算符 or、and 和 not 中,not 优先级最高,or 最低,按优先级升序排序为 or < and < not。在同一个表达式中同时出现 and 和 or 时,建议用加小括号的方法明确顺序,这样可以更准确的表达逻辑顺序,同时提高程序的可读性和易维护性。

print(1 or 0 and 2 )     # 输出 1
# 由于 or 优先级最低,最后参与运算,先计算0 and 2的值,整个表达式等价于在0 and 2上加括号
print(1 or (0 and 2))    # 输出 1
1
1

四、实例: 登录验证

用户名为admin和root的用户的密码均为“123456”。用户输入用户名与密码,当输入的用户名为admin或root,且密码为“123456”时,输出“登录成功”;否则输出“登录失败”。

user_name = input()
password = input()
if user_name == 'root' or 'admin' and password == '123456': # 等价于(user_name == 'root') or ('admin' and password == '123456')
    print('登录成功')
else:
    print('登录失败')
a
123456
登录成功

上面的代码中if后面的条件表达式等价于:

(user_name == 'root') or ('admin' and password == '123456')

or两边有一边为真时,就可以通过验证。当用户输入的用户名为root时,左边为True,or运算发生短路,略过右边表达式,所以不论密码输入什么也可登陆成功。当用户输入任意用户名时,or左边为False,这时表达式结果由右边and运算结果确定。因为and左边是a非空字符串“admin”,为True,那么只要右侧的比较运算结果为True,即只要密码输入正确,无论用户名是什么,都可以登陆成功,显然与题目要求不符。

user_name = input()
password = input()
if (user_name == 'root' or 'admin') and password == '123456': 
    print('登录成功')
else:
    print('登录失败')
abc
123456
登录成功

上面修改后的代码,表达式user_name == 'root' or 'admin'中字符串’admin’的真值测试结果为True,因此该表达式值恒为True,这时or左边的用户名验证会失效。无论用户输入任何用户名,只要密码输入正确即可登陆成功,显然与题目要求仍然不符。

正确的代码如下:

user_name = input()
password = input()
if (user_name == 'root' or user_name == 'admin') and password == '123456': 
    print('登录成功')
else:
    print('登录失败')
admin
123456
登录成功
user_name = input()
password = input()
if (user_name == 'admin' and password == '123456') or (user_name == 'root' and password == '123456'): 
    print('登录成功')
else:
    print('登录失败')
ro
123456
登录失败
user_name = input()
password = input()
if user_name == 'root' or user_name == 'admin':
    if password == '123456': 
        print('登录成功')
else:
    print('登录失败')

五、运算优先级

Python支持多种运算符的混合运算,所有运算符的优先级(由高到低排列)的描述如下表所示。

序号运算符描述
1()、[]、{}括号表达式,元组、列表、字典、集合显示
2x[i],x[m:n]索引、切片
3**幂运算
4~按位翻转
5+x、 -x正、负
6*、 / 、%乘法、除法与取模
7+ 、-加法与减法
8<< 、>>移位
9&按位与
10^按位异或
11|按位或
12<、<=、 >、 >=、 !=、 ==比较运算符
13is、 is not同一性测试
14in、not in成员测试
15not x逻辑非
16and逻辑与运算符
17or逻辑或运算符
18if…else条件表达式
19lambdalambda表达式
20:=赋值表达式、海象运算符
print(4 * 2 ** 3)      # 先幂运算,再计算乘法,输出:32
print(3 + 4 * -2)      # 2先取反、与4相乘,再做加法,输出:-5
print(3 + 4 * 2 / 2)   # 先计算乘除法,除法运算结果为浮点数,输出:7.0
print(3 << 2 + 1)      # 加法优先级高,先2+1,3(11)左移3位变成24 (11000)
32
-5
7.0
24

括号的优先级最高,可以强制表达式按照需要的顺序求值。可以通过加入小括号“()”的方法来提供弱优先级的优先执行。加了括号,无需比较哪个优先级更高,使程序和表达式更加易于阅读和维护。

六、实例:判断是否直角三角形

输入三个数a,b,c, 判断能否以它们为三个边长构成直角三角形。若能,输出YES,否则输出NO。

a = float(input())
b = float(input())
c = float(input())

# 三角形判定条件:边都为正数,任意两边之和大于第三边
if a <= 0 or b <= 0 or c <= 0 or (a + b) <= c or (a + c) <= b or (b + c) <= a:
    print('No')
# 直角三角形条件,两边平方和等于第三边
elif a * a + b * b == c * c or a * a + c * c == b * b or c * c + b * b == a * a:
    print('Yes')
else:
    print('No')
3
4
5
Yes

上面的代码中条件都比较长,可通过改进算法简化,代码如下:

a = float(input())
b = float(input())
c = float(input())

shortest = min(a, b, c)  # 获得最短边长度
longest = max(a, b, c)   # 获得最长边长度
middle = sum([a, b, c]) - shortest - longest

# 若最小边为负值或长边小于等于其他两边之和时,构不成三角形
if shortest <= 0 or shortest + middle <= longest:
    print('NO')
    
# 两边短边长度平方和等于第三边长度平方为直角三角形
elif shortest ** 2 + middle ** 2 == longest ** 2:
    print('YES')
    
else:
    print('NO')
3
4
5
YES
  • 9
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-北天-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值