第一章练习答案
本页提供第一章所有练习的参考答案和详细解释。建议先独立完成练习,再查看答案。
00-running-and-environment
练习 1:版本确认
python3 --version预期输出类似:Python 3.12.5 或更高版本。如果版本低于 3.10,建议从 python.org 安装最新版本。
练习 2:交互式计算
>>> (100 - 32) * 5 / 9
37.77777777777778结果是 float(浮点数),因为 / 运算符总是返回浮点数,即使操作数都是整数。
练习 3:第一个脚本
greet.py:
name = "Alice"
age = 30
print(f"{name} is {age} years old")运行:
python3 greet.py输出:
Alice is 30 years old修改 name 和 age 的值,重新运行会输出新的结果。这演示了如何通过修改变量值改变程序行为。
练习 4:观察缩进错误
bad_indent.py(错误版本):
x = 5
if x > 0:
print("positive")运行会报错:
File "bad_indent.py", line 3
print("positive")
^
IndentationError: expected an indented block after 'if' statement on line 2修正版本:
x = 5
if x > 0:
print("positive")关键:if 后的代码块必须缩进(通常 4 个空格)。
01-values-and-types
练习 1:身份与相等
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:不可变对象
x = 10
y = x
x = x + 5
print(y) # 输出: 10解释:
x = 10:x绑定到整数对象 10y = x:y也绑定到同一个整数对象 10x = x + 5:计算10 + 5创建新整数对象 15,x重新绑定到 15y仍然绑定到原来的对象 10,不受影响
整数是不可变的,x + 5 不会修改原对象,而是创建新对象。
练习 3:可变对象陷阱
list1 = [1, 2, 3]
list2 = list1
list2[0] = 999
print(list1) # [999, 2, 3]list1 和 list2 绑定到同一个列表对象,通过 list2 修改对象会影响 list1。
修正方法:创建副本
list1 = [1, 2, 3]
list2 = list1.copy() # 或 list2 = list1[:]
list2[0] = 999
print(list1) # [1, 2, 3]
print(list2) # [999, 2, 3]练习 4:类型检查
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")输出:
对象: 42
类型: <class 'int'>
是否为整数: True
是否为数字: True
对象: 3.14
类型: <class 'float'>
是否为整数: False
是否为数字: True
对象: hello
类型: <class 'str'>
是否为整数: False
是否为数字: False练习 5:小整数缓存边界
# 测试不同整数的身份
# 字面量赋值会被编译器优化,无法观察缓存边界
# 需要运行时构造来避免编译器常量复用
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):
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
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:质数判断
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:求和到阈值
total = 0
n = 1
while total <= 100:
total += n
n += 1
print(f"最后加入的数: {n - 1}")
print(f"总和: {total}")输出:
最后加入的数: 14
总和: 105解释:$1 + 2 + ... + 13 = 91$,加上 14 后总和为 105,超过 100。
练习 4:嵌套循环(乘法表)
for i in range(1, 10):
for j in range(1, 10):
print(f"{i}x{j}={i*j:2d}", end=" ")
print() # 换行输出(部分):
1x1= 1 1x2= 2 1x3= 3 1x4= 4 ...
2x1= 2 2x2= 4 2x3= 6 2x4= 8 ...
...{i*j:2d} 表示右对齐、宽度 2 的整数格式。
练习 5:else 子句
numbers = [2, 4, 6, 8, 10]
for num in numbers:
if num % 2 != 0:
print(f"找到奇数: {num}")
break
else:
print("所有数都是偶数")输出:
所有数都是偶数else 子句在循环正常结束(未 break)时执行。
03-operators-and-truthiness
练习 1:预测输出
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:短路验证
def side_effect():
print("副作用发生")
return True
result1 = False and side_effect() # 不打印,返回 False
result2 = True or side_effect() # 不打印,返回 True
result3 = True and side_effect() # 打印 "副作用发生",返回 Trueand 遇到假值、or 遇到真值时短路,不执行后续表达式。
练习 3:真值判断
print(bool([])) # False(空列表)
print(bool([0])) # True(非空列表)
print(bool("")) # False(空字符串)
print(bool(" ")) # True(包含空格,非空字符串)
print(bool(0.0)) # False(零)
print(bool(None)) # False(None)练习 4:优化条件
原代码:
age = 25
if age >= 18 and age <= 65:
if name != "" and name is not None:
print("有效用户")优化后:
age = 25
name = "Alice"
if 18 <= age <= 65 and name:
print("有效用户")改进:
- 使用链式比较
18 <= age <= 65 - 利用真值测试:
name为真当且仅当非空字符串且非 None
练习 5:三元表达式(绝对值)
x = -5
abs_x = x if x >= 0 else -x
print(abs_x) # 5或直接使用内置函数 abs(x)。
04-numbers-and-precision
练习 1:大整数计算
big = 2 ** 10000
num_digits = len(str(big))
print(f"2^10000 有 {num_digits} 位数字")输出:
2^10000 有 3011 位数字Python 的 int 是任意精度的,可以计算极大的整数。
练习 2:浮点精度
# 浮点精度问题
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:地板除与取模
seconds = 7385
hours = seconds // 3600
remainder = seconds % 3600
minutes = remainder // 60
secs = remainder % 60
print(f"{hours}小时 {minutes}分 {secs}秒")输出:
2小时 3分 5秒或使用 divmod 简化:
seconds = 7385
hours, remainder = divmod(seconds, 3600)
minutes, secs = divmod(remainder, 60)
print(f"{hours}小时 {minutes}分 {secs}秒")练习 4:货币计算
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}")输出:
小计: $37.79
税额: $3.21215
总计: $41.01练习 5:复数运算
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:数字验证
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)}")输出:
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 学习路线