Python 第三课:运算符、优先级与海象运算符
课程概述
本节课我们将全面学习 Python 中的运算符(Operators)。运算符是用于执行各种运算操作的符号,Python 提供了丰富的运算符,包括算术运算符、比较运算符、逻辑运算符、位运算符、赋值运算符、身份运算符和成员运算符。我们还将深入探讨运算符的优先级(Operator Precedence),理解 Python 如何按照固定的规则计算包含多个运算符的表达式。此外,本课将重点介绍 Python 3.8 引入的海象运算符(Walrus Operator),即赋值表达式(Assignment Expression),它允许在表达式内部进行变量赋值,是一个非常强大且实用的特性。本课程所有内容基于 Python 3.11 编写,涵盖了 Python 3.11 中运算符语法的最新变化和最佳实践。
Python 的运算符系统设计得既强大又优雅。Python 支持运算符重载(Operator Overloading),这意味着同一个运算符在不同数据类型上可能有不同的行为。例如,+ 运算符可以用于数字相加、字符串拼接、列表合并等多种场景,这种设计被称为"魔法方法"(Dunder Methods)或运算符重载。理解运算符的工作原理对于编写高效、简洁的 Python 代码至关重要。
算术运算符
算术运算符是最常用的运算符类型,用于执行基本的数学运算。
基本算术运算符
# 加减乘除
a, b = 15, 4
print(f"a = {a}, b = {b}")
print(f"a + b = {a + b}") # 19
print(f"a - b = {a - b}") # 11
print(f"a * b = {a * b}") # 60
print(f"a / b = {a / b:.4f}") # 3.7500(浮点除法)
# 整除(向下取整)
print(f"a // b = {a // b}") # 3
# 取余(模运算)
print(f"a % b = {a % b}") # 3(15 = 4 * 3 + 3)
# 幂运算(指数运算)
print(f"a ** b = {a ** b}") # 15^4 = 50625
# 负数运算
print(f"-a = {-a}") # -15
print(f"+a = {+a}") # 15(正号,一元运算符)
整数除法的特殊情况
# Python 3.11 中整数除法的行为
print(f"5 / 2 = {5 / 2}") # 2.5(总是返回浮点数)
print(f"5 // 2 = {5 // 2}") # 2(向下取整)
print(f"-5 // 2 = {-5 // 2}") # -3(向下取整,负数向更小的整数取整)
print(f"5 // -2 = {5 // -2}") # -3
print(f"-5 // -2 = {-5 // -2}") # 2
# 模运算与整除的关系
print(f"5 % 2 = {5 % 2}") # 1
print(f"-5 % 2 = {-5 % 2}") # 1(Python 保证 a % b 的符号与 b 相同)
print(f"5 % -2 = {5 % -2}") # -1
print(f"-5 % -2 = {-5 % -2}") # -1
算术运算符的组合赋值
# 组合赋值运算符
x = 10
print(f"初始 x = {x}")
x += 5 # 等价于 x = x + 5
print(f"x += 5 后,x = {x}")
x -= 3 # 等价于 x = x - 3
print(f"x -= 3 后,x = {x}")
x *= 2 # 等价于 x = x * 2
print(f"x *= 2 后,x = {x}")
x /= 4 # 等价于 x = x / 4
print(f"x /= 4 后,x = {x}")
x //= 2 # 等价于 x = x // 2
print(f"x //= 2 后,x = {x}")
x **= 3 # 等价于 x = x ** 3
print(f"x **= 3 后,x = {x}")
x %= 10 # 等价于 x = x % 10
print(f"x %= 10 后,x = {x}")
算术运算符的字符串和序列操作
# 字符串的乘法运算
text = "Python "
print(f"text * 3 = '{text * 3}'")
# 列表的加法和乘法
list1 = [1, 2, 3]
list2 = [4, 5, 6]
print(f"list1 + list2 = {list1 + list2}") # 列表拼接
print(f"list1 * 2 = {list1 * 2}") # 列表重复
# 元组的加法和乘法
t1 = (1, 2, 3)
t2 = (4, 5, 6)
print(f"t1 + t2 = {t1 + t2}")
print(f"t1 * 3 = {t1 * 3}")
比较运算符
比较运算符用于比较两个值的大小或相等性,返回布尔值(True 或 False)。
基本比较运算符
a, b = 10, 20
print(f"a = {a}, b = {b}")
print(f"a == b : {a == b}") # False(相等)
print(f"a != b : {a != b}") # True(不相等)
print(f"a < b : {a < b}") # True(小于)
print(f"a > b : {a > b}") # False(大于)
print(f"a <= b : {a <= b}") # True(小于等于)
print(f"a >= b : {a >= b}") # False(大于等于)
# 链式比较(Python 特有)
x = 15
print(f"10 < x < 20 : {10 < x < 20}") # True,等价于 (10 < x) and (x < 20)
print(f"10 < x < 15 : {10 < x < 15}") # False
比较运算符的字符串比较
s1, s2 = "apple", "banana"
print(f"s1 = '{s1}', s2 = '{s2}'")
print(f"s1 == s2 : {s1 == s2}") # False
print(f"s1 < s2 : {s1 < s2}") # True(字典序比较)
print(f"s1 > s2 : {s1 > s2}") # False
# 字符串比较是按字符逐个比较的
print(f"'apple' < 'apricot' : {'apple' < 'apricot'}") # True
# 不同类型之间的比较(谨慎使用)
print(f"10 < '20' : {10 < '20'}") # TypeError in Python 3.11
比较运算符的链式调用
Python 的链式比较是一个非常强大且优雅的特性,它不仅限于数值比较:
# 数值链式比较
x = 7
print(f"1 < x < 10 : {1 < x < 10}") # True
print(f"1 < x < 5 : {1 < x < 5}") # False
# 链式比较的原理
# 1 < x < 10 等价于 (1 < x) and (x < 10)
print(f"等价于:(1 < x) and (x < 10) = {(1 < x) and (x < 10)}")
# 三个以上的链式比较
y = 15
print(f"0 < x < 10 < y < 20 : {0 < x < 10 < y < 20}")
逻辑运算符
Python 提供了三个逻辑运算符:and(逻辑与)、or(逻辑或)和 not(逻辑非)。Python 3.11 对逻辑运算符的行为做了明确定义,特别是短路求值(Short-circuit Evaluation)的行为。
基本逻辑运算符
a, b = True, False
print(f"a = {a}, b = {b}")
print(f"a and b = {a and b}") # False
print(f"a or b = {a or b}") # True
print(f"not a = {not a}") # False
print(f"not b = {not b}") # True
# 逻辑运算符的优先级:not > and > or
print(f"not True or True : {not True or True}") # True
print(f"not (True or True) : {not (True or True)}") # False
短路求值(Short-circuit Evaluation)
短路求值是逻辑运算符的重要特性:对于 and 表达式,如果第一个值为 False,则不再计算第二个值,直接返回 False;对于 or 表达式,如果第一个值为 True,则不再计算第二个值,直接返回 True。
# and 的短路行为
def return_false():
print(" [调用 return_false()]")
return False
def return_true():
print(" [调用 return_true()]")
return True
print("测试 and 的短路求值:")
result = return_false() and return_true()
print(f"结果:{result}")
print()
print("由于第一个值为 False,return_true() 不会被调用")
print()
# or 的短路行为
print("测试 or 的短路求值:")
result = return_true() or return_false()
print(f"结果:{result}")
print()
print("由于第一个值为 True,return_false() 不会被调用")
逻辑运算符的应用场景
# 应用一:默认值赋值
name = None
# 如果 name 为 None 或空字符串,则使用 "Guest"
display_name = name or "Guest"
print(f"display_name = '{display_name}'")
name = "张三"
display_name = name or "Guest"
print(f"display_name = '{display_name}'")
# 应用二:链式条件检查
user_age = 25
has_license = True
if user_age >= 18 and has_license:
print("可以租车")
# 应用三:简化条件判断
is_weekend = False
is_holiday = True
is_vacation = False
if is_weekend or is_holiday or is_vacation:
print("今天休息")
# 应用四:区间判断
score = 85
if 60 <= score <= 100:
print("及格")
位运算符
位运算符用于对整数的二进制位进行操作,是低级编程和算法实现中的重要工具。Python 3.11 对位运算符的处理做了大量优化,特别是在处理大整数时。
基本位运算符
a, b = 10, 7 # a = 0b1010, b = 0b0111
print(f"a = {a} (二进制: {bin(a)})")
print(f"b = {b} (二进制: {bin(b)})")
print()
print(f"a & b = {a & b} (二进制: {bin(a & b)})") # 0b0010 = 2,按位与
print(f"a | b = {a | b} (二进制: {bin(a | b)})") # 0b1111 = 15,按位或
print(f"a ^ b = {a ^ b} (二进制: {bin(a ^ b)})") # 0b1101 = 13,按位异或
print(f"~a = {~a} (二进制: {bin(~a)})") # -11,按位取反
print(f"a << 1 = {a << 1} (二进制: {bin(a << 1)})") # 0b10100 = 20,左移
print(f"a >> 1 = {a >> 1} (二进制: {bin(a >> 1)})") # 0b0101 = 5,右移
位运算的实战应用
# 判断奇偶数(比 % 2 更快)
num = 42
is_even = (num & 1) == 0
print(f"{num} 是偶数:{is_even}")
# 快速乘除 2 的幂
n = 8
print(f"{n} << 2 = {n << 2}") # 乘以 4
print(f"{n} >> 2 = {n >> 2}") # 除以 4
# 交换两个整数(不使用临时变量)
x, y = 5, 9
x = x ^ y
y = x ^ y
x = x ^ y
print(f"交换后:x = {x}, y = {y}")
# 判断某个位是否为 1
flags = 0b10110010
bit_position = 3
is_set = (flags >> bit_position) & 1
print(f"第 {bit_position} 位是否为 1:{bool(is_set)}")
# 设置某个位为 1
flags = 0b10110010
bit_position = 1
flags = flags | (1 << bit_position)
print(f"设置第 {bit_position} 位为 1 后:{bin(flags)}")
赋值运算符(Assignment Operators)
基本赋值运算符
# 最基本的赋值
x = 10
print(f"x = {x}")
# 同时给多个变量赋值
a, b, c = 1, 2, 3
print(f"a, b, c = {a}, {b}, {c}")
# 链式赋值
x = y = z = 0
print(f"x = y = z = 0 => x={x}, y={y}, z={z}")
身份运算符(Identity Operators)
身份运算符用于比较两个对象的内存地址(id),判断它们是否是同一个对象。
is 与 is not
a = [1, 2, 3]
b = a # b 指向与 a 相同的对象
c = [1, 2, 3] # c 指向一个新创建的对象,内容相同但不是同一个对象
print(f"a = {a}")
print(f"b = a")
print(f"c = [1, 2, 3]")
print()
print(f"a is b : {a is b}") # True(同一对象)
print(f"a is c : {a is c}") # False(不同对象)
print(f"a == c : {a == c}") # True(内容相同)
print(f"a is not c : {a is not c}") # True(不是同一对象)
Python 3.11 中整数和字符串的小整数池
# Python 会缓存小的整数和短字符串
x = 256
y = 256
print(f"256 is 256 : {x is y}") # True(Python 缓存了 -5 到 256 的整数)
x = 257
y = 257
print(f"257 is 257 : {x is y}") # 可能为 False(取决于实现)
# 字符串 interning
s1 = "hello"
s2 = "hello"
print(f"'hello' is 'hello' : {s1 is s2}") # True(短字符串被缓存)
# 复杂表达式不会被 intern
s1 = "hello world"
s2 = "hello world"
print(f"'hello world' is 'hello world' : {s1 is s2}") # 通常为 False
成员运算符(Membership Operators)
成员运算符用于检查某个值是否存在于序列(列表、元组、字符串等)或集合中。
in 与 not in
# 列表中的成员检查
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
print(f"fruits = {fruits}")
print(f"'香蕉' in fruits : {'香蕉' in fruits}") # True
print(f"'西瓜' in fruits : {'西瓜' in fruits}") # False
print(f"'西瓜' not in fruits : {'西瓜' not in fruits}") # True
# 字符串中的成员检查
text = "Hello, Python 3.11!"
print(f"\ntext = '{text}'")
print(f"'Python' in text : {'Python' in text}") # True
print(f"'Java' in text : {'Java' in text}") # False
# 字典中检查的是键,不是值
person = {"name": "张三", "age": 25, "city": "北京"}
print(f"\nperson = {person}")
print(f"'name' in person : {'name' in person}") # True
print(f"'张三' in person : {'张三' in person}") # False(检查键而非值)
# 集合中的成员检查(非常高效)
prime_numbers = {2, 3, 5, 7, 11, 13}
print(f"\nprime_numbers = {prime_numbers}")
print(f"7 in prime_numbers : {7 in prime_numbers}") # True
print(f"4 in prime_numbers : {4 in prime_numbers}") # False
运算符优先级(Operator Precedence)
运算符优先级决定了表达式中多个运算符同时存在时的计算顺序。Python 按照从高到低的优先级计算表达式。了解运算符优先级对于正确理解复杂表达式至关重要。
完整优先级表
以下是从高到低的运算符优先级(同一行从左到右结合):
1. () 括号(最高优先级) 2. ** 幂运算(右结合) 3. +x, -x, ~x 一元正号、一元负号、按位取反 4. *, /, //, % 乘、除、整除、取余 5. +, - 加、减 6. <<, >> 位左移、位右移 7. & 按位与 8. ^ 按位异或 9. | 按位或 10. ==, !=, >, >=, <, <= 比较运算符 11. is, is not 身份运算符 12. in, not in 成员运算符 13. not 逻辑非 14. and 逻辑与 15. or 逻辑或 16. := 赋值表达式(海象运算符)(最低优先级之一)优先级示例
# 示例 1:幂运算的优先级高于乘法
result = 2 ** 3 * 2
print(f"2 ** 3 * 2 = {result}") # 8 * 2 = 16
print(f"等价于:(2 ** 3) * 2 = {(2 ** 3) * 2}")
# 示例 2:乘除优先于加减
result = 10 + 20 * 3 - 40 / 5
print(f"\n10 + 20 * 3 - 40 / 5 = {result}")
print(f"等价于:10 + (20 * 3) - (40 / 5) = {10 + (20 * 3) - (40 / 5)}")
# 示例 3:逻辑运算符的优先级
result = not True and False or True
print(f"\nnot True and False or True = {result}")
print(f"等价于:((not True) and False) or True = {((not True) and False) or True}")
# 示例 4:使用括号明确优先级
result = (2 + 3) * 4 ** 2 / (5 - 3)
print(f"\n(2 + 3) * 4 ** 2 / (5 - 3) = {result}")
# 示例 5:复杂的位运算优先级
a, b, c = 8, 4, 2
result = a | b ^ c & a
print(f"\na | b ^ c & a = {result}")
print(f"等价于:a | (b ^ (c & a)) = {a | (b ^ (c & a))}")
使用括号提高可读性
# 不好的写法(依赖优先级)
result = 10 + 20 * 2 ** 3 / 4 - 5 > 15 and True or False
# 好的写法(使用括号)
result = ((10 + (20 * (2 ** 3) / 4) - 5) > 15) and True or False
# 更可读的版本
left_side = 10 + (20 * (2 ** 3) / 4) - 5
condition = left_side > 15
result = condition and True or False
海象运算符(Walrus Operator):=
海象运算符(:=)是 Python 3.8 引入的赋值表达式(Assignment Expression)特性。它的名字来源于运算符的形状像一只海象侧躺的样子(:=)。海象运算符允许在表达式内部给变量赋值,从而可以编写更加简洁和优雅的代码。
为什么需要海象运算符?
在没有海象运算符之前,如果我们需要在一个条件判断中使用一个计算结果,必须先计算并存储到变量中,然后再使用这个变量进行判断:
# 没有海象运算符时的写法(Python 3.7 及之前)
data = [1, 5, 3, 9, 2, 8, 7]
result = [x for x in data if x > (sum(data) / len(data))]
# 或者需要分两行:
avg = sum(data) / len(data)
result = [x for x in data if x > avg]
海象运算符的基本用法
# 使用海象运算符,可以在列表推导式中同时计算和赋值
data = [1, 5, 3, 9, 2, 8, 7]
result = [x for x in data if x > (avg := sum(data) / len(data))]
print(f"平均值 = {avg:.2f}")
print(f"大于平均值的元素 = {result}")
# 在 while 循环中使用
# 没有海象运算符:
# line = input("> ")
# while line != "quit":
# print(f"你输入了:{line}")
# line = input("> ")
# 使用海象运算符:
while (line := input("> ")) != "quit":
print(f"你输入了:{line}")
# 正则表达式匹配中使用
import re
text = "Python 3.11 是 2022 年发布的"
pattern = r"Python (\d+\.\d+)"
match = re.search(pattern, text)
if match:
version = match.group(1)
print(f"找到 Python 版本:{version}")
# 使用海象运算符简化
if (match := re.search(pattern, text)):
print(f"找到 Python 版本:{match.group(1)}")
海象运算符的详细示例
# 示例 1:文件处理
# 传统写法:
with open("/tmp/test.txt", "w") as f:
for line in f:
line = line.strip()
if line:
print(line)
# 更简洁的写法(海象运算符)
with open("/tmp/test.txt", "w") as f:
while (line := f.readline()):
line = line.strip()
if line:
print(line)
# 示例 2:字典的 get 方法配合海象运算符
data = {"a": 1, "b": 2, "c": 3}
if (value := data.get("d")) is not None:
print(f"找到值:{value}")
else:
print("键 'd' 不存在,使用默认值 0")
value = 0
# 示例 3:重复调用函数时避免重复计算
import math
def expensive_computation(n):
"""模拟一个耗时的计算"""
print(f" [执行耗计算:sqrt({n})]")
return math.sqrt(n)
threshold = 10
numbers = [25, 4, 16, 100, 9]
# 传统写法:每次循环都调用函数
for n in numbers:
if expensive_computation(n) > threshold:
print(f" {n} 的平方根大于 {threshold}")
print()
# 使用海象运算符:只计算一次
for n in numbers:
if (result := expensive_computation(n)) > threshold:
print(f" {n} 的平方根({result:.2f})大于 {threshold}")
海象运算符的注意事项
# 注意 1:海象运算符有最低优先级之一
# x := a + b 会被解析为 x := (a + b)
# 而 x = a + b 也会被解析为 x = (a + b)
# 注意 2:在列表推导式中的变量作用域
# Python 3.11 中,列表推导式中的赋值表达式会让变量泄漏到外部作用域
result = [y := x**2 for x in range(5)]
print(f"结果:{result}")
print(f"y 的值:{y}") # y = 4**2 = 16(在 Python 3.11 中)
# 注意 3:不能在顶级表达式中使用(在交互式解释器中除外)
# print(y := 10) # 这是合法的
# 注意 4:不能在函数参数默认值中使用
# def func(x = y := 10): # SyntaxError
# 注意 5:不能在 lambda 表达式的主表达式中使用
# func = lambda x: y := x + 1 # SyntaxError
func = lambda x: (y := x + 1, y)[1] # 合法但不推荐
print(f"lambda: {func(5)}")
海象运算符的实际应用场景
# 场景 1:缓存计算结果
def fibonacci(n):
"""计算斐波那契数(带缓存的递归实现)"""
cache = {}
def _fib(n):
if n in cache:
return cache[n]
if n <= 1:
return n
cache[n] = _fib(n-1) + _fib(n-2)
return cache[n]
return _fib(n)
# 场景 2:条件表达式中的重复计算
# 没有海象运算符:
content = fetch_data() # 假设这是一个耗时的操作
if len(content) > 100:
print(f"数据过长:{len(content)} 个字符")
process(content)
else:
print("数据为空或太短")
# 使用海象运算符(Python 3.8+)
if (content := fetch_data()) and len(content) > 100:
print(f"数据过长:{len(content)} 个字符")
process(content)
elif content:
print("数据为空或太短")
# 场景 3:循环中的模式匹配
data = [1, 2, 3, "error", 4, 5, None, 6]
while (item := data.pop()) is not None:
print(f"处理数据:{item}")
Python 3.11 中的运算符改进
比较运算符的优化
Python 3.11 对比较运算符的实现进行了优化,特别是对于链式比较和复杂表达式的处理。以下是一些 Python 3.11 中值得注意的改进:
# Python 3.11 中链式比较的优化
a, b, c, d = 1, 2, 3, 4
# 链式比较现在有更清晰的错误信息
# 在 Python 3.11 中运行以下代码:
# 1 < "2" # TypeError: '<' not supported between instances of 'int' and 'str'
f-string 中的赋值表达式
Python 3.11 增强了 f-string 功能,其中一个重要的改进是支持在 f-string 中使用赋值表达式(海象运算符):
# Python 3.11 中 f-string 与海象运算符结合
name = "Python"
# 注意:在 f-string 中使用 := 有一些限制
# Python 3.11 中 f-string 的 := 用法:
x = 10
print(f"{x=}")
print(f"{x+5=}")
综合练习题
练习一:运算符综合应用
"""
运算符综合练习
练习各种运算符的使用和优先级
"""
def demonstrate_operators():
print("=" * 60)
print(" Python 运算符综合演示")
print("=" * 60)
# 算术运算符
print("\n【1. 算术运算符】")
a, b = 17, 5
print(f"a = {a}, b = {b}")
print(f"a + b = {a + b}")
print(f"a - b = {a - b}")
print(f"a * b = {a * b}")
print(f"a / b = {a / b:.4f}")
print(f"a // b = {a // b}")
print(f"a % b = {a % b}")
print(f"a ** b = {a ** b}")
# 比较运算符
print("\n【2. 比较运算符】")
print(f"a == b : {a == b}")
print(f"a != b : {a != b}")
print(f"a < b : {a < b}")
print(f"a > b : {a > b}")
print(f"a <= b : {a <= b}")
print(f"a >= b : {a >= b}")
# 逻辑运算符
print("\n【3. 逻辑运算符】")
x, y, z = 10, 20, 30
print(f"x = {x}, y = {y}, z = {z}")
print(f"(x < y) and (y < z) : {(x < y) and (y < z)}") # True
print(f"(x > y) or (y < z) : {(x > y) or (y < z)}") # True
print(f"not (x < y) : {not (x < y)}") # False
# 位运算符
print("\n【4. 位运算符】")
m, n = 12, 10 # 12 = 0b1100, 10 = 0b1010
print(f"m = {m} (0b{m:04b}), n = {n} (0b{n:04b})")
print(f"m & n = {m & n} (0b{m & n:04b})") # 0b1000 = 8
print(f"m | n = {m | n} (0b{m | n:04b})") # 0b1110 = 14
print(f"m ^ n = {m ^ n} (0b{m ^ n:04b})") # 0b0110 = 6
demonstrate_operators()
练习二:海象运算符实战
"""
海象运算符实战练习
演示 := 的各种使用场景
"""
def walrus_operator_demo():
print("=" * 60)
print(" 海象运算符(:=)实战演示")
print("=" * 60)
# 场景 1:列表推导式中的重复计算
print("\n【场景 1:避免重复计算】")
scores = [85, 92, 78, 95, 88, 73, 91, 80]
# 不使用海象运算符:avg 需要先计算
avg = sum(scores) / len(scores)
above_avg = [s for s in scores if s > avg]
print(f"分数列表:{scores}")
print(f"平均分:{avg:.2f}")
print(f"高于平均分的分数:{above_avg}")
# 使用海象运算符(一行搞定)
above_avg_v2 = [s for s in scores if s > (avg := sum(scores) / len(scores))]
print(f"使用海象运算符:{above_avg_v2}")
# 场景 2:while 循环中的输入处理
print("\n【场景 2:简化 while 循环】")
print("传统写法:")
print(" line = input('> ')")
print(" while line != 'quit':")
print(" print(f'你输入了:{line}')")
print(" line = input('> ')")
print("\n海象运算符写法:")
print(" while (line := input('> ')) != 'quit':")
print(" print(f'你输入了:{line}')")
# 场景 3:条件表达式中的赋值
print("\n【场景 3:条件赋值】")
data = {"x": 10, "y": 20, "z": 30}
# 查找并处理
if (value := data.get("x")) is not None:
print(f"找到 x = {value}, 平方 = {value**2}")
else:
print("未找到 x")
# 场景 4:with 语句中的资源管理
print("\n【场景 4:简化 with 语句】")
import io
buffer = io.StringIO()
buffer.write("Hello, ")
buffer.write("Python!")
buffer.seek(0)
content = buffer.read()
print(f"StringIO 内容:{content}")
walrus_operator_demo()
练习三:运算符优先级挑战
"""
运算符优先级挑战
通过实例理解复杂的运算符优先级
"""
def precedence_challenges():
print("=" * 60)
print(" 运算符优先级挑战")
print("=" * 60)
# 挑战 1
result = 2 ** 3 ** 2
print(f"\n2 ** 3 ** 2 = {result}") # 2 ** 9 = 512(右结合)
print(f"等价于:2 ** (3 ** 2) = {2 ** (3 ** 2)}")
# 挑战 2
result = -3 ** 2
print(f"\n-3 ** 2 = {result}") # -(3 ** 2) = -9(幂运算优先于一元负号)
print(f"等价于:-(3 ** 2) = {-(3 ** 2)}")
print(f"注意:(-3) ** 2 = {(-3) ** 2}") # 9
# 挑战 3
result = 5 - 3 + 2
print(f"\n5 - 3 + 2 = {result}") # (5 - 3) + 2 = 4(左结合)
print(f"5 - 3 - 2 = {5 - 3 - 2}") # (5 - 3) - 2 = 0
# 挑战 4
result = 10 / 3 + 3 * 2 ** 2 - 8 // 3
print(f"\n10 / 3 + 3 * 2 ** 2 - 8 // 3 = {result}")
print(f"等价于:(10 / 3) + (3 * (2 ** 2)) - (8 // 3)")
print(f" = {10 / 3} + {3 * 2 ** 2} - {8 // 3}")
print(f" = {10 / 3 + 3 * 2 ** 2 - 8 // 3}")
# 挑战 5
a = [1, 2, 3]
b = a
b[0] = 10
print(f"\n浅拷贝效果:a = {a}, b = {b}")
print(f"a == b : {a == b}") # True
print(f"a is b : {a is b}") # True(同一对象)
precedence_challenges()
常见错误与调试
错误一:浮点数比较
# 错误:直接比较浮点数
a = 0.1 + 0.2
print(f"a = {a}")
print(f"a == 0.3 : {a == 0.3}") # False
# 正确:使用 math.isclose 或 round
import math
print(f"math.isclose(a, 0.3) : {math.isclose(a, 0.3)}") # True
print(f"round(a, 10) == 0.3 : {round(a, 10) == 0.3}") # True
错误二:短路求值导致的变量未定义
# 错误:依赖短路求值但变量在条件分支中都未定义
# x = 10
# if x > 0 and y > 0: # NameError: name 'y' is not defined
# pass
# 正确:先检查变量是否存在
x, y = 10, 5
if x > 0 and y > 0:
print(f"x * y = {x * y}")
错误三:海象运算符优先级误解
# 错误理解
x = 5
# 期望:比较 x 和 3 + 2,然后赋值给 y
# 实际:
y := x > (3 + 2) # y 被赋值为 False
print(f"y = {y}")
# 正确理解::= 的优先级很低
(y := x > 3) + 2 # y = True (即 1),1 + 2 = 3
print(f"y = {y}")
本章小结
今天我们学习了以下核心内容:
- 算术运算符:加、减、乘、除、整除、取余、幂运算及其组合赋值形式。
- 比较运算符:相等、不等、小于、大于等,以及 Python 特有的链式比较。
- 逻辑运算符:
and、or、not,以及短路求值机制。 - 位运算符:按位与、或、异或、取反、左移、右移。
- 身份运算符:
is、is not,用于比较对象的内存地址。 - 成员运算符:
in、not in,用于检查成员资格。 - 运算符优先级:完整的优先级表和实际应用中的注意事项。
- 海象运算符(
:=):Python 3.8 引入的赋值表达式,简化代码编写。
下一节课我们将学习 Python 的条件语句(if-elif-else)和 Python 3.10 引入的结构化模式匹配(match-case),敬请期待!