Skip to content

第一章练习答案 ​

本页提供第一章所有练习的参考答案和详细解释。建议先独立完成练习,再查看答案。

00-running-and-environment ​

练习 1:版本确认 ​

bash
python3 --version

预期输出类似:Python 3.12.5 或更高版本。如果版本低于 3.10,建议从 python.org 安装最新版本。

练习 2:交互式计算 ​

python
>>> (100 - 32) * 5 / 9
37.77777777777778

结果是 float(浮点数),因为 / 运算符总是返回浮点数,即使操作数都是整数。

练习 3:第一个脚本 ​

greet.py:

python
name = "Alice"
age = 30
print(f"{name} is {age} years old")

运行:

bash
python3 greet.py

输出:

text
Alice is 30 years old

修改 name 和 age 的值,重新运行会输出新的结果。这演示了如何通过修改变量值改变程序行为。

练习 4:观察缩进错误 ​

bad_indent.py(错误版本):

python
x = 5
if x > 0:
print("positive")

运行会报错:

text
  File "bad_indent.py", line 3
    print("positive")
    ^
IndentationError: expected an indented block after 'if' statement on line 2

修正版本:

python
x = 5
if x > 0:
    print("positive")

关键:if 后的代码块必须缩进(通常 4 个空格)。


01-values-and-types ​

练习 1:身份与相等 ​

python
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(a == b)  # True:值相等
print(a is b)  # False:不是同一个对象
print(a is c)  # True:c 和 a 绑定到同一对象

解释:

  • a 和 b 是两个内容相同的列表对象,值相等但身份不同
  • c = a 让 c 绑定到 a 所指的对象,因此 a is c 为真

练习 2:不可变对象 ​

python
x = 10
y = x
x = x + 5
print(y)  # 输出: 10

解释:

  1. x = 10:x 绑定到整数对象 10
  2. y = x:y 也绑定到同一个整数对象 10
  3. x = x + 5:计算 10 + 5 创建新整数对象 15,x 重新绑定到 15
  4. y 仍然绑定到原来的对象 10,不受影响

整数是不可变的,x + 5 不会修改原对象,而是创建新对象。

练习 3:可变对象陷阱 ​

python
list1 = [1, 2, 3]
list2 = list1
list2[0] = 999
print(list1)  # [999, 2, 3]

list1 和 list2 绑定到同一个列表对象,通过 list2 修改对象会影响 list1。

修正方法:创建副本

python
list1 = [1, 2, 3]
list2 = list1.copy()  # 或 list2 = list1[:]
list2[0] = 999
print(list1)  # [1, 2, 3]
print(list2)  # [999, 2, 3]

练习 4:类型检查 ​

python
def check_type(obj):
    print(f"对象: {obj}")
    print(f"  类型: {type(obj)}")
    print(f"  是否为整数: {isinstance(obj, int)}")
    print(f"  是否为数字: {isinstance(obj, (int, float))}")
    print()

check_type(42)
check_type(3.14)
check_type("hello")

输出:

text
对象: 42
  类型: <class 'int'>
  是否为整数: True
  是否为数字: True

对象: 3.14
  类型: <class 'float'>
  是否为整数: False
  是否为数字: True

对象: hello
  类型: <class 'str'>
  是否为整数: False
  是否为数字: False

练习 5:小整数缓存边界 ​

python
# 测试不同整数的身份
# 字面量赋值会被编译器优化,无法观察缓存边界
# 需要运行时构造来避免编译器常量复用
for n in [255, 256, 257]:
    a = int(str(n))  # 运行时构造
    b = int(str(n))  # 运行时构造
    print(f"{n}: a is b = {a is b}")

输出(CPython 3.12):

text
255: a is b = True
256: a is b = True
257: a is b = False

关键点:

  • CPython 缓存 -5 到 256 的整数,这个范围内的值只有一个实例
  • 257 不在缓存范围内,两次运行时构造会产生不同对象
  • 如果直接写 a = 257; b = 257,编译器会优化为同一对象(常量折叠),输出 True
  • 这是 CPython 实现细节,不是语言契约。其他 Python 实现可能有不同的缓存策略

02-control-flow ​

练习 1:FizzBuzz ​

python
for i in range(1, 101):
    if i % 15 == 0:
        print("FizzBuzz")
    elif i % 3 == 0:
        print("Fizz")
    elif i % 5 == 0:
        print("Buzz")
    else:
        print(i)

关键:先检查 15 的倍数(既是 3 又是 5 的倍数),再分别检查 3 和 5。

练习 2:质数判断 ​

python
def is_prime(n):
    if n < 2:
        return False
    if n == 2:
        return True
    if n % 2 == 0:
        return False
    
    # 只需检查到 sqrt(n)
    for i in range(3, int(n**0.5) + 1, 2):
        if n % i == 0:
            return False
    return True

print(is_prime(17))  # True
print(is_prime(18))  # False
print(is_prime(2))   # True
print(is_prime(1))   # False

优化:

  • 特殊处理 2(唯一的偶数质数)
  • 排除所有偶数
  • 只检查到 $\sqrt{n}$

练习 3:求和到阈值 ​

python
total = 0
n = 1
while total <= 100:
    total += n
    n += 1

print(f"最后加入的数: {n - 1}")
print(f"总和: {total}")

输出:

text
最后加入的数: 14
总和: 105

解释:$1 + 2 + ... + 13 = 91$,加上 14 后总和为 105,超过 100。

练习 4:嵌套循环(乘法表) ​

python
for i in range(1, 10):
    for j in range(1, 10):
        print(f"{i}x{j}={i*j:2d}", end="  ")
    print()  # 换行

输出(部分):

text
1x1= 1  1x2= 2  1x3= 3  1x4= 4  ...
2x1= 2  2x2= 4  2x3= 6  2x4= 8  ...
...

{i*j:2d} 表示右对齐、宽度 2 的整数格式。

练习 5:else 子句 ​

python
numbers = [2, 4, 6, 8, 10]

for num in numbers:
    if num % 2 != 0:
        print(f"找到奇数: {num}")
        break
else:
    print("所有数都是偶数")

输出:

text
所有数都是偶数

else 子句在循环正常结束(未 break)时执行。


03-operators-and-truthiness ​

练习 1:预测输出 ​

python
print(0 or 5 or 10)              # 5(第一个真值)
print(10 and 20 and 0)           # 0(遇到假值)
print(not (5 > 3) or (2 < 1))    # False(not True = False, False or False = False)
print(1 < 2 < 3 < 4)             # True(链式比较全部满足)
print("" or [] or {} or 0 or "default")  # "default"(前面都是假值)

练习 2:短路验证 ​

python
def side_effect():
    print("副作用发生")
    return True

result1 = False and side_effect()  # 不打印,返回 False
result2 = True or side_effect()    # 不打印,返回 True
result3 = True and side_effect()   # 打印 "副作用发生",返回 True

and 遇到假值、or 遇到真值时短路,不执行后续表达式。

练习 3:真值判断 ​

python
print(bool([]))       # False(空列表)
print(bool([0]))      # True(非空列表)
print(bool(""))       # False(空字符串)
print(bool(" "))      # True(包含空格,非空字符串)
print(bool(0.0))      # False(零)
print(bool(None))     # False(None)

练习 4:优化条件 ​

原代码:

python
age = 25
if age >= 18 and age <= 65:
    if name != "" and name is not None:
        print("有效用户")

优化后:

python
age = 25
name = "Alice"

if 18 <= age <= 65 and name:
    print("有效用户")

改进:

  • 使用链式比较 18 <= age <= 65
  • 利用真值测试:name 为真当且仅当非空字符串且非 None

练习 5:三元表达式(绝对值) ​

python
x = -5
abs_x = x if x >= 0 else -x
print(abs_x)  # 5

或直接使用内置函数 abs(x)。


04-numbers-and-precision ​

练习 1:大整数计算 ​

python
big = 2 ** 10000
num_digits = len(str(big))
print(f"2^10000 有 {num_digits} 位数字")

输出:

text
2^10000 有 3011 位数字

Python 的 int 是任意精度的,可以计算极大的整数。

练习 2:浮点精度 ​

python
# 浮点精度问题
print((0.1 + 0.1 + 0.1) == 0.3)  # False(二进制表示误差)
print(0.1 * 3 == 0.3)             # False(同样有误差)

# 查看实际值
print(0.1 + 0.1 + 0.1)  # 0.30000000000000004
print(0.1 * 3)          # 0.30000000000000004
print(0.3)              # 0.3

# Python 3.12+ 的 sum() 使用改进算法(更高精度)
print(sum([0.1] * 10) == 1.0)    # True(Python 3.12+)
print(sum([0.1] * 10))            # 1.0

# Python 3.11 及之前版本:
# sum([0.1] * 10) 返回 0.9999999999999999

# 手动循环累加仍然有误差(未使用 sum 的改进算法)
result = 0.0
for _ in range(10):
    result += 0.1
print(result == 1.0)    # False
print(result)           # 0.9999999999999999

# 使用 math.fsum 可以在所有版本获得高精度
import math
print(math.fsum([0.1] * 10) == 1.0)  # True(所有版本)

浮点精度要点:

  • 0.1 无法用二进制精确表示,存储的是最接近的近似值
  • 累加或乘法都会产生误差累积
  • Python 3.12+:sum() 使用 Shewchuk 算法,浮点求和更精确
  • Python 3.11-:sum() 直接累加,累积误差更明显
  • 建议:需要高精度时使用 math.fsum() 或 decimal 模块,跨版本兼容

Python 3.12+ 的 sum() 对浮点数使用了改进的求和算法(Neumaier/Kahan),减少了累积误差。但直接的连续加法仍会产生误差。对精度要求高的场景使用 Decimal 或 math.fsum()。

练习 3:地板除与取模 ​

python
seconds = 7385
hours = seconds // 3600
remainder = seconds % 3600
minutes = remainder // 60
secs = remainder % 60
print(f"{hours}小时 {minutes}分 {secs}秒")

输出:

text
2小时 3分 5秒

或使用 divmod 简化:

python
seconds = 7385
hours, remainder = divmod(seconds, 3600)
minutes, secs = divmod(remainder, 60)
print(f"{hours}小时 {minutes}分 {secs}秒")

练习 4:货币计算 ​

python
from decimal import Decimal

prices = [Decimal('19.99'), Decimal('5.50'), Decimal('12.30')]
subtotal = sum(prices)
tax_rate = Decimal('0.085')
tax = subtotal * tax_rate
total = subtotal + tax
total_rounded = total.quantize(Decimal('0.01'))

print(f"小计: ${subtotal}")
print(f"税额: ${tax}")
print(f"总计: ${total_rounded}")

输出:

text
小计: $37.79
税额: $3.21215
总计: $41.01

练习 5:复数运算 ​

python
z1 = 1 + 2j
z2 = 3 - 4j
result = z1 * z2
print(result)  # (11+2j)

验证:$(1+2i)(3-4i) = 3 - 4i + 6i - 8i^2 = 3 + 2i + 8 = 11 + 2i$

练习 6:数字验证 ​

python
from decimal import Decimal, InvalidOperation

def check_numeric(s):
    results = {}
    
    # 检查整数
    try:
        int(s)
        results['int'] = True
    except ValueError:
        results['int'] = False
    
    # 检查浮点数
    try:
        float(s)
        results['float'] = True
    except ValueError:
        results['float'] = False
    
    # 检查 Decimal
    try:
        Decimal(s)
        results['decimal'] = True
    except InvalidOperation:
        results['decimal'] = False
    
    return results

# 测试
test_cases = ["123", "3.14", "abc", "inf", "1.23e-4"]
for case in test_cases:
    print(f"{case}: {check_numeric(case)}")

输出:

text
123: {'int': True, 'float': True, 'decimal': True}
3.14: {'int': False, 'float': True, 'decimal': True}
abc: {'int': False, 'float': False, 'decimal': False}
inf: {'int': False, 'float': True, 'decimal': True}
1.23e-4: {'int': False, 'float': True, 'decimal': True}

本章完成 ​

完成这些练习后,你已经掌握了 Python 的基础:运行环境、对象模型、控制流、运算符、数字类型。继续第二章学习函数与作用域。

回到第一章概览 · 返回Python 学习路线

用心记录每一步成长