1. Objectives 学习目标
- To understand definite and indefinite loops using
forandwhile理解使用for和while的确定循环和不确定循环 - To understand interactive loops and sentinel loops using
while理解使用while的交互循环和哨兵循环 - To understand end-of-file loops and their implementation 理解文件结束循环及其实现
- To design and implement solutions with nested loop structures 设计和实现嵌套循环结构的解决方案
2. Definite Loops 确定循环
For Loops: A Quick Review for循环快速回顾
for <var> in <sequence>:
<body>特点: 循环次数在循环开始时确定
Example: Average Calculator 示例:平均值计算器
# 计算用户输入数字的平均值
def main():
n = int(input("How many numbers? "))
total = 0.0
for i in range(n):
number = float(input("Enter a number: "))
total = total + number
print("The average is:", total/n)
if __name__ == '__main__':
main()文件读取示例:计算成绩平均值
# 读取文件中的成绩并计算平均值
def calculate_average():
total = 0.0
count = 0
with open('grades.txt', 'r') as file:
for line in file:
grade = float(line.strip())
total += grade
count += 1
if count > 0:
average = total / count
print(f"Ming's average grade is: {average:.2f}")
else:
print("No grades found in the file.")2.1 Exercises 练习
Exercise 1: Count Words with ‘p’ 练习1:统计包含’p’的单词
def count_words_with_p():
count = 0
with open('story.txt', 'r') as file:
text = file.read()
words = text.split()
for word in words:
if 'p' in word.lower():
count += 1
print(f"Number of words containing 'p': {count}")
# 使用while循环实现
def count_words_with_p_while():
count = 0
with open('story.txt', 'r') as file:
text = file.read()
words = text.split()
i = 0
while i < len(words):
if 'p' in words[i].lower():
count += 1
i += 1
print(f"Number of words containing 'p': {count}")Exercise 2: Multiplication Table 练习2:乘法表
def multiplication_table():
for i in range(1, 10):
for j in range(1, i + 1):
print(f"{j}×{i}={i*j:2d}", end=" ")
print() # 换行
# 输出:
# 1×1= 1
# 1×2= 2 2×2= 4
# 1×3= 3 2×3= 6 3×3= 9
# ...Exercise 3: Prime Number Check 练习3:质数检查
def prime_check():
for num in range(2, 11):
is_prime = True
factors = []
for i in range(2, num):
if num % i == 0:
is_prime = False
factors.append(i)
if is_prime:
print(f"{num} is prime")
else:
print(f"{num} = {factors}")
# 优化版本
def prime_check_optimized():
for num in range(2, 11):
factors = []
for i in range(2, int(num**0.5) + 1):
if num % i == 0:
factors.extend([i, num//i])
if not factors:
print(f"{num} is prime")
else:
# 去重并排序
unique_factors = sorted(set(factors))
print(f"{num} = {unique_factors}")Exercise 4: String Split and Pad 练习4:字符串分割和填充
def split_strings():
result = []
while True:
s = input("Enter a string (empty to stop): ")
if not s:
break
# 按长度8分割
for i in range(0, len(s), 8):
chunk = s[i:i+8]
# 长度不足8时补0
if len(chunk) < 8:
chunk = chunk.ljust(8, '0')
result.append(chunk)
print("Result:", result)
# 示例输入输出
# 输入: "1234567890", "abc"
# 输出: ['12345678', '90000000', 'abc00000']3. Indefinite Loops 不确定循环
While Loop while循环
while <condition>:
<body>特点: 前置测试循环(pre-test loop),条件为真时继续执行
While与for对比
# for循环
for i in range(11):
print(i)
# while循环等价实现
i = 0
while i <= 10:
print(i)
i = i + 1无限循环警告
# 错误示例 - 无限循环
i = 0
while i <= 10:
print(i)
# 缺少 i = i + 1
# 解决方法:Ctrl+C, Ctrl+Alt+Delete, 或重启Number Guessing Game 猜数字游戏
import random
def guessing_game():
# 生成随机数
secret_number = random.randint(0, 100)
attempts = 0
print("I'm thinking of a number between 0 and 100. Can you guess it?")
while True:
try:
guess = int(input("Enter your guess: "))
attempts += 1
if guess == secret_number:
print(f"Success! You guessed it in {attempts} attempts.")
break
elif guess < secret_number:
print("Too small! Try again.")
else:
print("Too big! Try again.")
except ValueError:
print("Please enter a valid number.")
if __name__ == '__main__':
guessing_game()4. Loop Control Statements 循环控制语句
Break Statement break语句
# 在列表中找到特定课程
courses = ["Math", "Physics", "Python Programming", "Chemistry", "Biology"]
for course in courses:
if course == "Python Programming":
print("Found the Python Programming course!")
break
print(f"Checking: {course}")
# 输出:
# Checking: Math
# Checking: Physics
# Found the Python Programming course!Continue Statement continue语句
# 跳过特定课程
courses = ["Math", "Physics", "Python Programming", "Chemistry", "Biology"]
for course in courses:
if course == "Python Programming":
continue # 跳过Python课程
print(f"Studying: {course}")
# 输出:
# Studying: Math
# Studying: Physics
# Studying: Chemistry
# Studying: BiologyElse Clause with Loops 循环的else子句
在循环正常结束时执行
# 在循环正常结束时执行
numbers = [2, 4, 6, 8, 10]
for num in numbers:
if num % 2 != 0:
print("Found an odd number!")
break
else:
print("All numbers are even!") # 会执行
# 搜索示例
search_item = "Python"
items = ["Java", "C++", "JavaScript"]
for item in items:
if item == search_item:
print(f"Found {search_item}!")
break
else:
print(f"{search_item} not found in the list.") # 会执行5. Boolean Operations 布尔运算
Boolean Operators 布尔运算符
# 运算符优先级: not > and > or
result1 = True or not False and True # 等价于 True or ((not False) and True)
result2 = (True or (not False)) and True
print(result1) # True
print(result2) # TrueBoolean Algebra 布尔代数
# 德摩根定律应用
scoreA, scoreB = 10, 12
# 原始复杂条件
if not(scoreA == 15 or scoreB == 15):
print("Game continues")
# 应用德摩根定律简化
if scoreA != 15 and scoreB != 15:
print("Game continues - simplified")
# 其他布尔恒等式
a = True
print(a or True) # True
print(not(not a)) # True (双重否定)
print(not(a and False)) # TrueShort-circuit Evaluation 短路求值
# 使用or设置默认值
flavor = input("What flavor do you want [vanilla]: ") or "vanilla"
print(f"You chose: {flavor}")
# 等价的长版本
user_input = input("What flavor do you want [vanilla]: ")
if user_input:
flavor = user_input
else:
flavor = "vanilla"6. Loop Patterns 循环模式
Interactive Loops 交互循环
def interactive_average():
total = 0.0
count = 0
more_data = "yes"
while more_data[0].lower() == "y":
number = float(input("Enter a number: "))
total += number
count += 1
more_data = input("Do you have more numbers (yes or no)? ")
if count > 0:
print(f"The average is {total/count}")
else:
print("No numbers were entered.")
# 测试运行:
# Enter a number >> 32
# Do you have more numbers (yes or no)? y
# Enter a number >> 45
# Do you have more numbers (yes or no)? yes
# Enter a number >> 34
# The average of the numbers is 37.0Sentinel Loops 哨兵循环
def sentinel_average():
total = 0.0
count = 0
print("Enter numbers (negative to quit):")
number = float(input("Enter a number: "))
while number >= 0:
total += number
count += 1
number = float(input("Enter a number: "))
if count > 0:
print(f"The average is {total/count}")
else:
print("No numbers were entered.")
# 改进版本 - 使用字符串哨兵
def sentinel_average_improved():
total = 0.0
count = 0
while True:
input_str = input("Enter a number (<Enter> to quit): ")
if input_str == "":
break
number = float(input_str)
total += number
count += 1
if count > 0:
print(f"The average is {total/count}")File Loops 文件循环
def file_average():
total = 0.0
count = 0
with open('numbers.txt', 'r') as infile:
for line in infile:
number = float(line.strip())
total += number
count += 1
if count > 0:
print(f"The average is {total/count}")
# 使用readline的版本
def file_average_readline():
total = 0.0
count = 0
with open('numbers.txt', 'r') as infile:
line = infile.readline()
while line != "":
number = float(line.strip())
total += number
count += 1
line = infile.readline()
if count > 0:
print(f"The average is {total/count}")Nested Loops 嵌套循环
def process_csv_file():
total = 0.0
count = 0
with open('data.csv', 'r') as infile:
line = infile.readline()
while line != "":
# 外层循环:处理每一行
numbers = line.strip().split(',')
# 内层循环:处理行中的每个数字
for num_str in numbers:
if num_str: # 确保不是空字符串
total += float(num_str)
count += 1
line = infile.readline()
if count > 0:
print(f"The average is {total/count}")
# 处理每行多个数字的CSV文件
# 文件内容示例:
# 10,20,30
# 40,50
# 60,70,80,907. Post-Test Loops 后测试循环
Input Validation 输入验证
# 方法1:使用标志变量
def get_positive_number_v1():
number = -1 # 初始化为非法值
while number < 0:
number = float(input("Enter a positive number: "))
if number < 0:
print("The number must be positive!")
return number
# 方法2:使用break(推荐)
def get_positive_number_v2():
while True:
number = float(input("Enter a positive number: "))
if number >= 0:
break
print("The number must be positive!")
return numberLoop and a Half 循环中途模式
def sentinel_loop_elegant():
total = 0.0
count = 0
while True:
data = input("Enter a number (or 'done' to finish): ")
if data.lower() == 'done':
break # 哨兵值,不处理
number = float(data)
total += number
count += 1
if count > 0:
print(f"The average is {total/count}")7.1 Example: Event Loop 示例:事件循环
Simple GUI Event Loop 简单GUI事件循环
from graphics import *
def simple_event_loop():
win = GraphWin("Color Changer", 400, 300)
win.setBackground("white")
instructions = Text(Point(200, 20), "Press r(red), g(green), b(blue), q(quit)")
instructions.draw(win)
while True:
key = win.checkKey()
if key == "q":
break
elif key == "r":
win.setBackground("pink")
elif key == "g":
win.setBackground("lightgray")
elif key == "b":
win.setBackground("lightblue")
# 检查鼠标点击
click = win.checkMouse()
if click:
handle_click(click, win)
win.close()
def handle_click(point, window):
# 在点击位置创建输入框
entry = Entry(point, 10)
entry.draw(window)
# 进入文本输入模式
while True:
key = window.getKey()
if key == "Return":
break
# 获取文本并显示
text = entry.getText()
entry.undraw()
display_text = Text(point, text)
display_text.draw(window)
if __name__ == '__main__':
simple_event_loop()7.2 Data Analysis Example: S&P 500 数据分析示例:标普500
S&P 500 Industry Analysis 标普500行业分析
import matplotlib.pyplot as plt
import csv
from tkinter.filedialog import askopenfilename
def sp500_analysis():
# 文件选择循环
while True:
filename = askopenfilename(title="Select CSV file", filetypes=[("CSV files", "*.csv")])
if filename and filename.endswith('.csv'):
break
print("Please select a valid CSV file.")
# 读取和分析数据
sectors = {}
with open(filename, 'r', encoding='utf-8') as file:
reader = csv.DictReader(file)
for row in reader:
sector = row.get('Sector', 'Unknown')
market_cap = float(row.get('Market Cap', 0))
if sector not in sectors:
sectors[sector] = {'count': 0, 'market_cap': 0}
sectors[sector]['count'] += 1
sectors[sector]['market_cap'] += market_cap
# 用户交互循环
while True:
choice = input("Number of stocks (N) or Market Capitalization (M) (Enter for exit): ")
if choice == '':
break
elif choice.upper() == 'N':
plot_sector_counts(sectors)
elif choice.upper() == 'M':
plot_market_share(sectors)
else:
print("Wrong input, please try again.")
def plot_sector_counts(sectors):
labels = list(sectors.keys())
counts = [sectors[sector]['count'] for sector in labels]
plt.figure(figsize=(10, 8))
plt.pie(counts, labels=labels, autopct='%1.1f')
plt.title('S&P 500 Market Capitalization by Sector')
plt.show()
if __name__ == '__main__':
sp500_analysis()8. Summary 总结
Loop Types 循环类型
- Definite loops确定循环:
forloops with known iterations 已知迭代次数的for循环 - Indefinite loops不确定循环:
whileloops with conditions 基于条件的while循环 - Interactive loops交互循环: User-controlled repetition 用户控制的重复
- Sentinel loops哨兵循环: Special value terminates 特殊值终止
- File loops文件循环: Process until end of file 处理直到文件结束
- Nested loops嵌套循环: Loops within loops 循环中的循环
Control Statements 控制语句
break: Exit loop immediately 立即退出循环continue: Skip to next iteration 跳到下一次迭代else: Execute after normal completion 正常完成后执行
Best Practices 最佳实践
- Use meaningful loop variable names 使用有意义的循环变量名
- Avoid infinite loops with proper termination conditions 使用适当的终止条件避免无限循环
- Use
breaksparingly for clarity 谨慎使用break以保持清晰度 - Prefer
forloops when number of iterations is known 当迭代次数已知时优先使用for循环 - Validate input in post-test loops 在后测试循环中验证输入
Ex. 补充:列表推导式 (List Comprehensions)
基础语法
[p.x for p in points] # 从points列表中提取每个对象的x属性详细解释
基本用法
# 假设我们有一个Point类
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
# 创建点列表
points = [Point(1, 2), Point(3, 4), Point(5, 6)]
# 使用列表推导式提取所有x坐标
x_coordinates = [p.x for p in points]
print(x_coordinates) # 输出: [1, 3, 5]
# 等价于传统的for循环
x_coordinates_manual = []
for p in points:
x_coordinates_manual.append(p.x)在数据分析中的应用
# 从学生对象列表中提取成绩
class Student:
def __init__(self, name, grade):
self.name = name
self.grade = grade
students = [
Student("Alice", 85),
Student("Bob", 92),
Student("Charlie", 78)
]
# 提取所有成绩
grades = [s.grade for s in students]
print(grades) # [85, 92, 78]
# 计算平均成绩
average_grade = sum([s.grade for s in students]) / len(students)
print(f"Average grade: {average_grade:.2f}")带条件的列表推导式
# 只提取及格成绩
passing_grades = [s.grade for s in students if s.grade >= 80]
print(passing_grades) # [85, 92]
# 提取优秀学生的名字
top_students = [s.name for s in students if s.grade >= 90]
print(top_students) # ['Bob']与循环结构的对比
# 传统方法 - 需要多行代码
def get_x_coordinates_traditional(points):
result = []
for p in points:
result.append(p.x)
return result
# 列表推导式 - 一行搞定
def get_x_coordinates_comprehension(points):
return [p.x for p in points]
# 两者功能完全相同,但列表推导式更简洁在文件处理中的应用
# 从文件中读取数字并转换为浮点数
def read_numbers_from_file(filename):
with open(filename, 'r') as file:
# 使用列表推导式处理每一行
numbers = [float(line.strip()) for line in file if line.strip()]
return numbers
# 等价于
def read_numbers_traditional(filename):
numbers = []
with open(filename, 'r') as file:
for line in file:
if line.strip(): # 跳过空行
numbers.append(float(line.strip()))
return numbers嵌套列表推导式
# 处理二维数据
class DataPoint:
def __init__(self, values):
self.values = values
data_points = [
DataPoint([1, 2, 3]),
DataPoint([4, 5, 6]),
DataPoint([7, 8, 9])
]
# 提取所有值并展平
all_values = [value for dp in data_points for value in dp.values]
print(all_values) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 提取每个数据点的第一个值
first_values = [dp.values[0] for dp in data_points]
print(first_values) # [1, 4, 7]在S&P 500分析中的应用
# 使用列表推导式简化之前的S&P 500分析代码
def sp500_analysis_improved():
filename = askopenfilename(title="Select CSV file", filetypes=[("CSV files", "*.csv")])
with open(filename, 'r', encoding='utf-8') as file:
reader = csv.DictReader(file)
# 使用列表推导式一次性读取所有行
rows = [row for row in reader]
# 使用列表推导式提取所有行业
sectors = list(set([row.get('Sector', 'Unknown') for row in rows]))
# 使用列表推导式计算每个行业的公司数量
sector_counts = {sector: len([row for row in rows if row.get('Sector') == sector])
for sector in sectors}
# 使用列表推导式计算每个行业的总市值
sector_market_caps = {
sector: sum([float(row.get('Market Cap', 0))
for row in rows if row.get('Sector') == sector])
for sector in sectors
}性能优势
import time
# 列表推导式通常比传统循环更快
def benchmark_comprehension():
points = [Point(i, i*2) for i in range(1000000)]
# 方法1: 列表推导式
start = time.time()
x_coords = [p.x for p in points]
time1 = time.time() - start
# 方法2: 传统循环
start = time.time()
x_coords_manual = []
for p in points:
x_coords_manual.append(p.x)
time2 = time.time() - start
print(f"列表推导式: {time1:.4f}秒")
print(f"传统循环: {time2:.4f}秒")
print(f"速度提升: {time2/time1:.2f}x")总结
[p.x for p in points]是Python的列表推导式语法- 用于从可迭代对象中快速提取属性或转换数据
- 比传统for循环更简洁、易读、高效
- 可以结合条件语句进行过滤
- 在数据分析、文件处理等场景中广泛应用
- 是Pythonic编程的重要特性之一
这种语法体现了Python的”简洁优雅”哲学,让代码更加Pythonic!