【Python】流程控制语句之循环结构

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 == 3break 触发,循环直接终止,不会执行 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 可迭代对象:
    代码块
  • 变量:每次循环都会取出 可迭代对象 中的一个元素,赋值给 变量
  • 可迭代对象:可以被遍历的对象,如 listtuplestrrange()dict
  • 代码块:对 变量 进行的操作,必须缩进

2. else 结束时执行

else 语句可以与 forwhile 循环一起使用,它的作用是当循环正常结束时执行。注意: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)

#输出:苹果
  • 由于 breakfruit == "香蕉" 时触发,循环被提前终止,因此只输出了 "苹果"

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(起始值,终止值)

如果提供两个参数 startstop,则循环从 start 开始:

for i in range(2, 7):
    print(i)

输出

2
3
4
5
6
  • 2 开始,不包含 7

4. 三参数的range(起始值,终止值,步长)

你可以使用 steprange() 每次递增不同的数:

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 是对应的值。
  • indexfruit 分别表示索引和值。

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) 将两个列表按位置配对,生成一个元组的迭代器。每个元组包含来自 namesscores 的一对元素。

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_unpackedscores_unpacked 分别存储 namesscores 的元素。

5. 遍历多个可迭代对象

通过 zip(),你可以同时遍历多个可迭代对象,而不需要使用索引。

names = ["小明", "小红", "小刚"]
scores = [90, 85, 88]

for name, score in zip(names, scores):
    print(f"{name} 的分数是 {score}")

输出

小明 的分数是 90小红 的分数是 85小刚 的分数是 88

解释

  • zip(names, scores) 创建一个迭代器,能够同时返回 namesscores 中的元素。

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 后的地方提前终止,迭代器对象(如 rangelist 等)就不再被使用,内存得以释放。
  • 性能分析

    • 如果循环中包含 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 本身不会影响程序的性能,但它保证了代码结构的完整性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值