4、基础语法速通(二):条件判断、循环与异常处理
好,咱们接着聊。上一章我们把变量、数据类型和运算符过了一遍,算是把地基打好了。这一章,我们要让脚本真正“活”起来——能根据情况做决策,能重复干一件事,还能在出错时优雅地收场。
说白了,条件判断、循环和异常处理,就是脚本的“大脑”、“肌肉”和“安全气囊”。没有它们,你的脚本就是一潭死水。
4.1 条件判断:让脚本学会“看人下菜碟”
运维脚本里,最常干的事就是“如果……就……”。比如:
“如果磁盘使用率超过90%,就发告警。”
“如果服务挂了,就重启它。”
“如果用户是管理员,就让他执行,否则拒绝。”
这些逻辑,在Python里全靠 if、elif、else 来实现。
4.1.1 基础语法
结构很简单,记住这个模板就行:
if 条件1:
执行代码块1
elif 条件2:
执行代码块2
else:
执行代码块3
注意,Python用缩进来划分代码块,不是花括号。我刚开始从C语言转过来时,老不习惯,经常因为缩进不对报错。后来养成了习惯:统一用4个空格,不用Tab。
来看个实际例子:
disk_usage = 85 # 磁盘使用率百分比
if disk_usage > 90:
print("⚠️ 磁盘告警!赶紧处理!")
elif disk_usage > 80:
print("⚠️ 磁盘使用率偏高,建议关注。")
else:
print("✅ 磁盘状态正常。")
输出结果:⚠️ 磁盘使用率偏高,建议关注。
4.1.2 多条件组合
有时候一个条件不够,需要同时满足多个条件。用 and、or、not 来组合:
cpu_load = 5.0
mem_usage = 70
# 两个条件都满足才告警
if cpu_load > 4.0 and mem_usage > 80:
print("⚠️ 系统资源紧张!")
else:
print("✅ 系统运行平稳。")
这里 and 表示“并且”,or 表示“或者”。not 就是取反,比如 if not status 表示“如果状态为假”。
if a == None,用 if a is None。前者是值比较,后者是身份比较。在Python里,None是单例对象,用 is 更安全、更规范。
4.2 循环:让脚本学会“重复劳动”
运维里最烦什么?重复操作。比如批量检查100台服务器的状态,总不能一台一台手动执行吧?循环就是干这个的。
Python提供了两种循环:for 和 while。
4.2.1 for 循环:遍历一切
for 循环适合遍历列表、字典、字符串等可迭代对象。我个人觉得,80%的循环场景用 for 就够了。
遍历列表:
servers = ["web01", "web02", "db01", "cache01"]
for server in servers:
print(f"正在检查 {server} 的状态...")
# 这里可以写检查逻辑
遍历字典:
config = {
"host": "192.168.1.100",
"port": 3306,
"user": "admin"
}
for key, value in config.items():
print(f"{key} = {value}")
配合 range() 生成数字序列:
# 打印1到5
for i in range(1, 6):
print(f"第 {i} 次尝试...")
你想想看,range(1, 6) 为什么是1到5,不是1到6?因为Python的区间是“左闭右开”,这是很多新手容易懵的地方。
4.2.2 while 循环:条件驱动
while 循环适合“不知道要循环多少次,但知道什么时候停止”的场景。比如等待某个服务启动:
import time
service_ready = False
retry_count = 0
while not service_ready and retry_count < 5:
print(f"等待服务启动... 第 {retry_count + 1} 次检查")
# 模拟检查服务状态
time.sleep(2)
retry_count += 1
# 假设第3次检查时服务就绪
if retry_count == 3:
service_ready = True
if service_ready:
print("✅ 服务已就绪!")
else:
print("❌ 服务启动超时!")
while 循环时,一定要确保循环条件最终会变成 False,否则就是死循环。我见过有人写 while True: 忘了加 break,结果脚本跑了一整夜,把日志文件撑爆了。
4.2.3 循环控制:break 和 continue
break 是“立即终止整个循环”,continue 是“跳过本次,继续下一次”。
# 找到第一个CPU使用率超过90%的服务器就停止
servers = [("web01", 45), ("web02", 92), ("web03", 78)]
for name, cpu in servers:
if cpu > 90:
print(f"发现高负载服务器:{name},CPU使用率 {cpu}%")
break # 找到了,不再继续
print(f"{name} 正常,继续检查...")
输出:
web01 正常,继续检查...
发现高负载服务器:web02,CPU使用率 92%
4.3 异常处理:给脚本穿上“防弹衣”
运维脚本跑在真实环境里,什么意外都可能发生:网络断了、磁盘满了、配置文件格式错了……如果不处理异常,脚本直接崩溃,留下一堆莫名其妙的报错。
异常处理就是给脚本穿上防弹衣,让它遇到问题时能优雅地处理,而不是直接“躺平”。
4.3.1 try/except 基础
基本结构:
try:
# 可能会出错的代码
result = 10 / 0
except ZeroDivisionError:
# 出错时执行的代码
print("❌ 除数不能为0!")
你可以捕获多种异常:
try:
num = int(input("请输入一个数字:"))
result = 100 / num
print(f"结果是:{result}")
except ValueError:
print("❌ 输入的不是有效数字!")
except ZeroDivisionError:
print("❌ 不能输入0!")
except Exception as e:
print(f"❌ 发生了未知错误:{e}")
最后那个 except Exception as e 是“兜底”的,捕获所有没被前面捕获的异常。我建议每个 try 块都加上这个,防止漏网之鱼。
except Exception 来隐藏所有错误。正确的做法是:先捕获你能预见的特定异常(比如 FileNotFoundError、ConnectionError),最后再用 Exception 兜底。这样既安全,又不会掩盖真正的bug。
4.3.2 else 和 finally
else 块:当 try 块没有发生异常时执行。
finally 块:不管有没有异常,都会执行。常用于清理资源,比如关闭文件、断开数据库连接。
try:
file = open("config.txt", "r")
content = file.read()
except FileNotFoundError:
print("❌ 配置文件不存在!")
else:
print("✅ 配置文件读取成功!")
print(content)
finally:
print("🔚 清理工作:关闭文件")
file.close() # 确保文件一定被关闭
你想想看,finally 是不是很像“无论结果如何,都要善后”的承诺?在运维脚本里,这个特性特别重要。比如你临时修改了防火墙规则,不管脚本执行成功还是失败,最后都要恢复规则。
4.3.3 主动抛出异常
有时候,你想主动告诉调用者“这里出问题了”。用 raise 关键字:
def check_disk(usage):
if usage > 95:
raise ValueError(f"磁盘使用率 {usage}% 超过阈值!")
return True
try:
check_disk(98)
except ValueError as e:
print(f"告警:{e}")
这样做的好处是:把“判断逻辑”和“处理逻辑”分开了。函数只负责检查并抛出异常,调用者决定怎么处理。代码更干净,也更灵活。
except 块里又写了可能出错的代码,结果异常没处理好,反而引发了新的异常。记住:except 块里的代码也要考虑异常处理,或者尽量简单,只做日志记录和状态标记。
4.4 综合实战:一个简单的健康检查脚本
把今天学的串起来,写个实用的例子:
import time
def check_server(ip):
"""模拟检查服务器状态"""
# 假设只有192.168.1.2会超时
if ip == "192.168.1.2":
raise TimeoutError(f"{ip} 连接超时!")
return True
servers = ["192.168.1.1", "192.168.1.2", "192.168.1.3"]
max_retries = 3
for server in servers:
success = False
for attempt in range(1, max_retries + 1):
try:
print(f"检查 {server}... 第 {attempt} 次尝试")
check_server(server)
print(f"✅ {server} 正常")
success = True
break # 成功就跳出重试循环
except TimeoutError as e:
print(f"⚠️ {e}")
if attempt < max_retries:
print("等待3秒后重试...")
time.sleep(3)
else:
print(f"❌ {server} 检查失败,已达最大重试次数")
if not success:
# 记录失败日志
with open("failed_servers.log", "a") as log:
log.write(f"{server} 检查失败\n")
print(f"已将 {server} 记录到失败日志")
print("🎉 所有服务器检查完毕!")
这个脚本里,for 循环遍历服务器列表,try/except 处理超时异常,break 在成功时跳出重试循环,else 配合 if 判断是否记录失败日志。你看,条件判断、循环、异常处理全用上了。
嗯,这一章的内容就到这里。说白了,这三个语法就是运维脚本的“三板斧”。你写100个脚本,99个都离不开它们。下一章,我们会聊聊函数和模块——怎么把代码组织得更优雅,怎么复用已有的轮子。
记住:多写、多练、多踩坑。踩过的坑,都是你成长的阶梯。