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}")

本章小结

今天我们学习了以下核心内容:

  1. 算术运算符:加、减、乘、除、整除、取余、幂运算及其组合赋值形式。
  2. 比较运算符:相等、不等、小于、大于等,以及 Python 特有的链式比较。
  3. 逻辑运算符andornot,以及短路求值机制。
  4. 位运算符:按位与、或、异或、取反、左移、右移。
  5. 身份运算符isis not,用于比较对象的内存地址。
  6. 成员运算符innot in,用于检查成员资格。
  7. 运算符优先级:完整的优先级表和实际应用中的注意事项。
  8. 海象运算符:=):Python 3.8 引入的赋值表达式,简化代码编写。

下一节课我们将学习 Python 的条件语句(if-elif-else)和 Python 3.10 引入的结构化模式匹配(match-case),敬请期待!

延伸阅读