while
循环(基于条件的循环)
1. 基本语法
while 条件:
循环体
条件
:一个布尔表达式,如果为True
,则执行循环体;如果为False
,则退出循环。循环体
:满足条件时要执行的代码块。
2 . else
条件为假时执行
Python 的 while
循环可以搭配 else
,当 while
正常执行完毕后,else
语句会执行;如果循环因 break
退出,则 else
不执行。
num = 1
while num <= 3:
print("当前数值:", num)
num += 1
else:
print("循环结束")
输出:
当前数值: 1
当前数值: 2
当前数值: 3
循环结束
3 . break
退出循环
break
用于立即终止 while
循环,不执行 else
代码块。
num = 1
while num <= 5:
if num == 3:
print("遇到 3,退出循环")
break
print("当前数值:", num)
num += 1
else:
print("循环正常结束")
print("循环外的代码")
输出:
当前数值: 1
当前数值: 2
遇到 3,退出循环
循环外的代码
解释:
num == 3
时break
触发,循环直接终止,不会执行else
语句。
4 . continue
跳过当前循环
continue
语句用于跳过当前循环的剩余代码,直接进入下一次循环。
num = 0
while num < 5:
num += 1
if num == 3:
print("跳过 3")
continue
print("当前数值:", num)
输出:
当前数值: 1
当前数值: 2
跳过 3
当前数值: 4
当前数值: 5
解释:
num == 3
时,continue
使循环跳过print("当前数值:", num)
,直接进入下一次循环。
5. pass
空循环
可以用 pass
来创建一个空的 while
循环,表示等待某个事件发生或等待条件变为 True
。
i = 0
while i < 5:
pass # 暂时不做任何事,空循环
i += 1
print("循环结束")
#输出:循环结束
解释:
- 这个循环会无限次地检查
i
是否小于 5,并且每次执行时,pass
占位,什么也不做。循环会一直运行,直到i
自增至 5。
示例:搭配 input()
可以使用 while
不断读取用户输入,直到用户输入 exit
退出。
while True:
user_input = input("请输入内容(输入 'exit' 退出):")
if user_input == "exit":
print("退出程序")
break
print("你输入了:", user_input)
解释:
while True:
形成无限循环。input()
获取用户输入。- 如果用户输入
"exit"
,break
退出循环。
示例:猜数字游戏
import random
num = random.randint(1, 10)
guess = 0
while guess != num:
guess = int(input("猜一个 1-10 之间的数字:"))
if guess < num:
print("太小了")
elif guess > num:
print("太大了")
else:
print("恭喜你,猜对了!")
解析:
random.randint(1, 10)
生成 1~10 之间的随机数。- 用户输入值
guess
,与num
进行比较,直到guess == num
时退出。
示例:生成斐波那契数列
使用 while
生成 斐波那契数列(Fibonacci Sequence) :
a, b = 0, 1
while b < 50:
print(b, end=" ")
a, b = b, a + b
# 输出:1 1 2 3 5 8 13 21 34
解释:
a, b = 0, 1
:初始值。b = a + b
计算下一个斐波那契数。
问题: while
无限循环
如果 while
条件始终为 True
,循环不会终止,形成无限循环。
while True:
print("这是一个无限循环")
- 无限循环会占用 CPU 资源,需要用
break
终止,或者手动停止程序(Ctrl + C
)。
for
循环(基于迭代的循环)
for
循环是一种 遍历(Iteration) 结构,用于依次取出 可迭代对象(Iterable) 的元素,并对其执行指定的操作。
1 . 语法格式
for 变量 in 可迭代对象:
代码块
变量
:每次循环都会取出可迭代对象
中的一个元素,赋值给变量
可迭代对象
:可以被遍历的对象,如list
、tuple
、str
、range()
、dict
代码块
:对变量
进行的操作,必须缩进
2. else
结束时执行
else
语句可以与 for
和 while
循环一起使用,它的作用是当循环正常结束时执行。注意:else
中的代码不会在循环被 break
语句提前终止时执行。
fruits = ["苹果", "香蕉", "橙子"]
for fruit in fruits:
if fruit == "香蕉":
print("找到香蕉了!")
break
else:
print("没有找到香蕉!") # 如果没有 break,执行这个 else
#输出:找到香蕉了
- 因为在循环中遇到了
"香蕉"
,所以执行了break
,导致else
不会被执行。
3 . break
语句
break
用于终止当前循环(无论是 for
还是 while
),跳出循环体。它通常用在特定条件满足时,提前结束循环。
fruits = ["苹果", "香蕉", "橙子"]
for fruit in fruits:
if fruit == "香蕉":
break # 当遇到"香蕉"时,结束循环
print(fruit)
#输出:苹果
- 由于
break
在fruit == "香蕉"
时触发,循环被提前终止,因此只输出了"苹果"
。
4. continue
跳过当前循环
假设我们有一个列表,需要打印列表中的所有偶数,但跳过所有奇数。可以使用 continue
来实现。
numbers = [1, 2, 3, 4, 5, 6]
for num in numbers:
if num % 2 != 0:
continue # 如果是奇数,跳过本次迭代
print(num)
输出:
2
4
6
解释:
continue
语句使得循环跳过了奇数,直接进入下一个数字的判断。
5. pass
空循环
有时我们需要一个占位的循环,暂时不做任何处理,可以使用 pass
:
if condition:
pass # 这里不执行任何操作,保留结构
解释:
- 这个
for
循环没有执行任何操作,pass
只是占据了语法位置。
遍历列表
fruits = ["苹果", "香蕉", "橙子"]
for fruit in fruits:
print(fruit)
输出:
苹果
香蕉
橙子
遍历字符串
text = "Python"
for char in text:
print(char)
输出:
P
y
t
h
o
n
遍历元组
tup = (10, 20, 30)
for num in tup:
print(num)
解释:
10
20
30
遍历字典
student = {"name": "Alice", "age": 20, "score": 90}
for key, value in student.items():
print(f"{key}: {value}")
输出
name: Alice
age: 20
score: 90
遍历集合
numbers = {1, 2, 3}
for num in numbers:
print(num)
输出: (集合是无序的)
1
2
3
range()
高级循环
在 Python 中,for
语句通常与 range()
结合使用来进行循环。range()
生成一个可迭代的数列,而 for
循环会逐个取出其中的值执行代码块。
1. 基础语法
for 变量 in range(起始, 终止, 步长):
代码块
起始
(可选):从哪里开始,默认是0
终止
(必填):循环会到达的数字(不包含此数字)步长
(可选):每次递增或递减的数值,默认为1
2. 单参数的 range(终止值)
如果只给 range()
传递一个数值 n
,则默认从 0
开始,到 n-1
结束:
for i in range(5):
print(i)
输出:
0
1
2
3
4
- 等价于
range(0, 5, 1)
3. 两参数的 range(起始值,终止值)
如果提供两个参数 start
和 stop
,则循环从 start
开始:
for i in range(2, 7):
print(i)
输出
2
3
4
5
6
- 从
2
开始,不包含7
4. 三参数的range(起始值,终止值,步长)
你可以使用 step
让 range()
每次递增不同的数:
for i in range(1, 10, 2):
print(i)
输出:
1
3
5
7
9
- 从
1
开始,每次加2
,直到小于10
5. range()
生成倒序数列
如果 step
设为负数,就能实现反向循环:
for i in range(10, 0, -2):
print(i)
输出:
10
8
6
4
2
- 从
10
开始,每次减2
,直到大于0
6 . for
和 range()
遍历列表索引
有时候,我们需要用 for
访问列表中的每个元素:
fruits = ["苹果", "香蕉", "橙子"]
for i in range(len(fruits)):
print(f"索引 {i}: {fruits[i]}")
输出:
索引 0: 苹果
索引 1: 香蕉
索引 2: 橙子
range(len(fruits))
生成[0, 1, 2]
作为索引
7. 列表推导式
如果只是想快速生成新列表,可以用 列表推导式:
squared = [num ** 2 for num in range(1, 6)]
print(squared)
输出:
[1, 4, 9, 16, 25]
等价于:
squared = []
for num in range(1, 6):
squared.append(num ** 2)
示例:九九乘法表
用双重 for
生成 九九乘法表:
for i in range(1, 10):
for j in range(1, i + 1):
print(f"{j}×{i}={i * j}", end="\t")
print()
输出:
1×1=1
1×2=2 2×2=4
1×3=3 2×3=6 3×3=9
...
- 外层
for
控制行,内层for
控制列
示例:求 1~100 之间的偶数和
total = 0
for num in range(2, 101, 2):
total += num
print("1~100 之间偶数的和:", total)
输出:
1~100 之间偶数的和: 2550
- 使用
range(2, 101, 2)
快速遍历偶数
示例:统计字符串中字母的个数
text = "Hello World!"
count = 0
for char in text:
if char.isalpha(): # 判断是否是字母
count += 1
print("字母的个数:", count)
输出:
字母的个数: 10
示例:反转字符串
text = "Python"
reversed_text = ""
for char in text:
reversed_text = char + reversed_text
print(reversed_text)
输出:
nohtyP
enumerate()
遍历索引和值
enumerate()
是 Python 内置的一个函数,它主要用于在遍历一个可迭代对象(如列表、元组、字符串等)时,能够同时返回该元素的索引和对应的值。这个功能避免了我们需要手动使用 range()
和 len()
来同时获取元素和索引的麻烦。
1. 基本的语法
enumerate(遍历对象, 起始值=0)
- 遍历对象:是任何可迭代对象,例如列表、字符串、元组等。
- 起始值:这是索引的起始值,默认为 0。如果你想从其他数字开始索引,可以指定它。
enumerate()
返回一个enumerate
类型的对象,实际上是一个迭代器。每次迭代时,它会返回一个二元组(索引, 值)
:
2. 单参数的enumerate(遍历对象)
假设我们有一个列表 fruits = ["苹果", "香蕉", "橙子"]
,我们想要遍历列表,并且同时获取每个元素的索引和值。
fruits = ["苹果", "香蕉", "橙子"]
for index, fruit in enumerate(fruits):
print(f"索引 {index}: {fruit}")
输出:
索引 0: 苹果
索引 1: 香蕉
索引 2: 橙子
解释:
enumerate(fruits)
生成了一个迭代器,每次迭代返回一个二元组(index, fruit)
,其中index
是元素的索引,fruit
是对应的值。index
和fruit
分别表示索引和值。
3. 双参数的enumerate(遍历对象,起始值)
有时候我们需要从一个特定的数字开始索引,而不是从默认的 0
开始。我们可以通过 start
参数来实现。
fruits = ["苹果", "香蕉", "橙子"]
for index, fruit in enumerate(fruits, start=1):
print(f"序号 {index}: {fruit}")
输出:
序号 1: 苹果
序号 2: 香蕉
序号 3: 橙子
解释:
enumerate(fruits, start=1)
指定了从1
开始计数。
4. 遍历字符串
enumerate()
不仅限于列表,也可以用于遍历其他可迭代对象,比如字符串。
word = "Python"
for index, char in enumerate(word):
print(f"索引 {index}: {char}")
输出:
索引 0: P
索引 1: y
索引 2: t
索引 3: h
索引 4: o
索引 5: n
解释:
- 遍历字符串
word = "Python"
,enumerate()
同样返回每个字符的索引和值。
5. 遍历字典
字典是 Python 中一个常见的数据结构,字典的元素是键值对。如果我们想同时获取字典的索引和值(键值对),可以通过 enumerate()
和字典的 .items()
方法结合使用:
person = {"name": "小明", "age": 18, "city": "上海"}
for index, (key, value) in enumerate(person.items()):
print(f"索引 {index}: {key} = {value}")
输出:
索引 0: name = 小明
索引 1: age = 18
索引 2: city = 上海
解释:
person.items()
返回字典的键值对,通过enumerate()
获取每个键值对的索引和值。
6. 列表推导式
如果你需要用索引和对应的值生成一个新的列表,可以结合 enumerate()
使用列表推导式:
fruits = ["苹果", "香蕉", "橙子"]
indexed_fruits = [(i, fruit) for i, fruit in enumerate(fruits)]
print(indexed_fruits)
输出:
[(0, '苹果'), (1, '香蕉'), (2, '橙子')]
7. 用于字典的构建
enumerate()
还可以帮助我们构建以索引为键、元素为值的字典:
fruits = ["苹果", "香蕉", "橙子"]
fruit_dict = {index: fruit for index, fruit in enumerate(fruits)}
print(fruit_dict)
输出:
{0: '苹果', 1: '香蕉', 2: '橙子'}
8. 与 next()
配合使用
enumerate()
可以与 next()
函数结合使用,获取可迭代对象中的下一个元素及其索引:
fruits = ["苹果", "香蕉", "橙子"]
fruit_enum = enumerate(fruits)
print(next(fruit_enum)) # (0, '苹果')
print(next(fruit_enum)) # (1, '香蕉')
print(next(fruit_enum)) # (2, '橙子')
zip()
并行迭代多个序列
zip()
是 Python 的内置函数,用于将多个可迭代对象(如列表、元组等)逐一配对,生成一个由元组组成的迭代器。每个元组包含来自各个输入可迭代对象的一个元素,zip()
会将这些元素按位置对齐。它常用于并行遍历多个可迭代对象。
1. 基本语法
zip(*迭代对象) # "*" 操作符会解包这个可迭代对象
zip(迭代对象1,迭代对象2,迭代对象3,.......)
- 迭代对象:例如列表、元组、字符串等。如果传入多个可迭代对象,
zip()
会按顺序从每个可迭代对象中提取元素,直到最短的可迭代对象耗尽。 zip()
返回一个 zip 对象,它是一个迭代器,每次迭代会返回一个元组,元组的元素是从各个可迭代对象中获取的对应位置的元素。你可以使用list()
或tuple()
将zip
对象转换为列表或元组。
2. 将两个列表配对
names = ["小明", "小红", "小刚"]
scores = [90, 85, 88]
result = zip(names, scores)
print(list(result)) # 转换为列表
输出:
[('小明', 90), ('小红', 85), ('小刚', 88)]
解释:
zip(names, scores)
将两个列表按位置配对,生成一个元组的迭代器。每个元组包含来自names
和scores
的一对元素。
3. 处理不同长度的可迭代对象
如果传入的可迭代对象长度不一样,zip()
会按最短的可迭代对象的长度进行配对,忽略多余的元素。
names = ["小明", "小红", "小刚"]
scores = [90, 85]
result = zip(names, scores)
print(list(result))
输出:
[('小明', 90), ('小红', 85)]
解释:
- 因为
scores
列表的长度为 2,zip()
会只配对前 2 个元素,忽略names
中的第三个元素。
4 . 解压配对元素
你可以使用 zip()
和 *
操作符(解包)来将配对的元素解开,将它们分别放入不同的列表或元组中。
names = ["小明", "小红", "小刚"]
scores = [90, 85, 88]
zipped = zip(names, scores)
names_unpacked, scores_unpacked = zip(*zipped)
print(names_unpacked) # ('小明', '小红', '小刚')
print(scores_unpacked) # (90, 85, 88)
输出:
('小明', '小红', '小刚')
(90, 85, 88)
解释:
zip(*zipped)
用来将配对的元组解开,使得names_unpacked
和scores_unpacked
分别存储names
和scores
的元素。
5. 遍历多个可迭代对象
通过 zip()
,你可以同时遍历多个可迭代对象,而不需要使用索引。
names = ["小明", "小红", "小刚"]
scores = [90, 85, 88]
for name, score in zip(names, scores):
print(f"{name} 的分数是 {score}")
输出:
小明 的分数是 90小红 的分数是 85小刚 的分数是 88
解释:
zip(names, scores)
创建一个迭代器,能够同时返回names
和scores
中的元素。
6. 用 zip()
创建字典
zip()
可以与字典的构造方法结合使用,生成一个字典,其中每个元组的第一个元素作为键,第二个元素作为值。
names = ["小明", "小红", "小刚"]
scores = [90, 85, 88]
student_dict = dict(zip(names, scores))
print(student_dict)
输出:
{'小明': 90, '小红': 85, '小刚': 88}
解释:
zip(names, scores)
生成一系列元组,然后通过dict()
将这些元组转换为字典。
循环控制语句(深度剖析)
break
语句(提前结束循环)
1. 作用
break
语句用于提前终止循环,它会立刻停止当前的循环迭代,控制权跳到循环体外的下一个语句。
2. 内存表现与性能分析
-
内存表现:
break
语句不会引起额外的内存分配或释放,因为它只是直接跳出循环,并且不再占用与循环相关的内存资源。- 比如在
for
循环中,一旦执行到break
,迭代器会被清除,不再继续生成新的元素。因此,如果循环在break
后的地方提前终止,迭代器对象(如range
、list
等)就不再被使用,内存得以释放。
-
性能分析:
- 如果循环中包含
break
,而循环本来是要进行大量迭代的,break
会提前跳出循环,这会显著减少无谓的计算。 - 举个例子,如果我们在遍历一个非常大的数据集合时,找到符合条件的元素就立即退出,避免了不必要的遍历,显著提升了程序效率。
例如,遍历一个 1 亿个元素的列表,寻找某个特定元素,如果使用
break
,只要找到了就终止,不再继续迭代后续的元素。 - 如果循环中包含
3. 性能优化案例
假设我们有一个非常大的列表,我们想要查找某个数字的位置:
# 查找第一个大于100的元素
numbers = list(range(10**7)) # 一个包含 1000 万个元素的列表
for num in numbers:
if num > 100:
print(f"找到了: {num}")
break # 发现就立即退出循环
- 在没有
break
的情况下,循环会遍历整个numbers
列表,直到找到符合条件的元素。 - 加入
break
后,程序找到符合条件的第一个元素,就会立即跳出循环,避免继续遍历后面的无用元素。此举能够节省大量的时间和计算资源,尤其是当数据量非常大的时候。
continue
语句(跳过当前循环)
1. 作用
continue
语句用于跳过当前循环中的剩余代码,继续进行下一次循环。它不会终止整个循环,而是继续迭代。
2. 内存表现与性能分析
-
内存表现:
continue
语句本身不会造成额外的内存消耗,因为它只是跳过当前的循环体内的剩余代码,控制权直接跳回到循环的顶部,进入下一次迭代。- 对于
for
循环来说,continue
后,迭代器状态不变,下一次循环继续执行;对于while
循环,continue
使得循环条件重新检查。
-
性能分析:
- 如果在每次迭代中,有多个
if
判断语句,并且在某些条件下跳过迭代(使用continue
),这种方式不会中断整个循环,因此它的性能比break
略低。 - 虽然
continue
在跳过某些不必要的部分时能节省一些执行时间,但它并没有像break
那样直接减少迭代次数,所以性能提升较小。
- 如果在每次迭代中,有多个
3. 性能优化案例
假设我们有一个条件较多的迭代操作,可以利用 continue
优化跳过无效部分:
# 跳过偶数,打印所有奇数
for i in range(10):
if i % 2 == 0:
continue # 偶数跳过
print(i)
- 在这里,
continue
语句可以跳过偶数的迭代,避免了打印偶数的操作,提升了一部分性能,但本质上整个for
循环还是需要迭代 10 次,因此性能提升是有限的。
else
与循环配合(循环正常执行完才执行 else
)
1. 作用
在 Python 中,else
可以与 for
循环和 while
循环一起使用。当循环正常结束时,else
代码块会被执行;但如果循环是通过 break
被中断的,else
代码块则不会被执行。
2. 内存表现与性能分析
-
内存表现:
else
本身不会引起额外的内存分配,因为它只是与循环结构相关联的代码块。它在内存中的行为与普通的控制语句类似,只是标识了在循环正常结束时需要执行的操作。else
语句会在循环结束后执行,因此它的内存占用是相对较小的,只要循环体内的内存已经被释放。
-
性能分析:
- 使用
else
不会直接影响循环的性能,因为else
只是提供了一种方式来执行循环后的某些操作。 else
在循环体内的逻辑执行时不会产生额外的性能负担。但如果用不当,else
可能导致代码逻辑不清晰,增加理解和维护的难度。- 如果你依赖
else
来检测是否遇到break
,在某些场景中可能会增加额外的判断逻辑,使得代码稍显复杂。不过,这种使用方式可以有效减少代码的重复度。
- 使用
3. 性能优化案例
举个例子,如果我们需要在某个循环中查找是否存在符合条件的元素,我们可以使用 else
来避免写额外的标志变量,提升代码可读性。
# 查找列表中是否存在偶数
numbers = [1, 3, 5, 7, 9, 10]
for num in numbers:
if num % 2 == 0:
print(f"找到了偶数: {num}")
break # 找到后退出循环
else:
print("没有找到偶数")
- 在这个例子中,
else
语句只有在for
循环没有遇到break
才会执行。如果列表中的所有数字都是奇数,else
中的代码会被执行,打印“没有找到偶数”。 else
语句在没有break
的情况下,能避免我们使用额外的标志变量来标记是否找到了符合条件的元素。
pass
语句(占位符)
1. 作用
pass
语句是一个占位符,它什么也不做。它通常在需要语法结构但不需要实际代码的情况下使用。
2. 内存管理与性能影响
-
内存表现:
pass
本身不会消耗任何额外的内存,因为它只是一个占位符,告诉 Python 不执行任何操作。- 它的内存消耗几乎为零,因为 Python 只需要在语法上识别它作为有效的语句,而不会进行任何的内存分配或操作。
-
性能分析:
pass
不会增加性能或减少性能,它仅作为语法上的占位符。因此,它对循环的性能没有影响,只会影响代码的可读性。- 在实际应用中,如果你用
pass
作为空函数或空类的占位符,它可能导致空循环的执行,但本身并不做任何工作,内存占用非常低。
3. 性能优化案例
假设我们在开发过程中创建了一个占位符函数:
def process_data(data): pass # 将来会实现数据处理逻辑
- 这个
process_data
函数并没有执行任何操作,但它依然是一个有效的函数定义。虽然pass
本身不会影响程序的性能,但它保证了代码结构的完整性。