Appearance
基础语法
Python 基础语法覆盖变量、类型、条件、循环、函数、异常和退出码。运维脚本经常处理命令输出、JSON、接口响应和批量主机列表,这些内容都建立在基础语法上。
Python 代码最明显的特点是缩进。缩进不是排版习惯,而是语法结构的一部分。if、for、def 下面的代码块都靠缩进表示归属。
一、变量与类型
Python 不需要声明类型,赋值即定义。
python
service_name = "nginx" # str,字符串
port = 80 # int,整数
load_avg = 0.78 # float,浮点数
enabled = True # bool,布尔值
last_error = None # NoneType,表示没有值type() 可以查看变量当前类型:
python
print(type(port)) # <class 'int'>变量名通常用小写加下划线,例如 service_name、max_retry。脚本跑起来以后,变量名就是排查时的上下文,名字清楚比缩写省下来的几个字符更重要。
常见类型:
| 类型 | 示例 | 运维场景 |
|---|---|---|
str | "mysql" | 服务名、路径、命令输出 |
int | 3306 | 端口、次数、状态码 |
float | 0.95 | CPU 使用率、延迟 |
bool | True / False | 开关、检查结果 |
None | None | 没有查到值、默认空值 |
二、字符串
运维脚本里字符串用得很多:路径、命令、日志、URL、错误信息都属于字符串。
2.1 f-string
f-string 可以把变量嵌进字符串:
python
service = "nginx"
port = 80
message = f"{service} listens on port {port}"
print(message) # nginx listens on port 80花括号里可以写简单表达式:
python
used = 8589934592
print(f"used={used // (1024 ** 3)}GB") # used=8GB格式化小数:
python
cpu_usage = 83.126
print(f"cpu={cpu_usage:.2f}%") # cpu=83.13%2.2 常用方法
python
line = " ERROR disk full "
clean_line = line.strip() # 去掉首尾空白
level = clean_line.split()[0] # 按空白切分,取第一个字段
lower_line = clean_line.lower() # 转小写,便于统一比较
has_error = clean_line.startswith("ERROR")
print(level, lower_line, has_error)几个方法的用途:
| 方法 | 用途 |
|---|---|
strip() | 去首尾空白和换行 |
split() | 切分日志行、命令输出 |
replace() | 替换字符串 |
startswith() | 判断前缀 |
endswith() | 判断后缀 |
lower() / upper() | 统一大小写 |
2.3 多行字符串
三引号保留换行,适合写多行配置模板或测试日志:
python
config = """server {
listen 80;
server_name example.com;
}
"""
print(config)三、运算符
基础运算:
python
print(10 + 3) # 13
print(10 - 3) # 7
print(10 * 3) # 30
print(10 / 3) # 3.333...
print(10 // 3) # 3,整除
print(10 % 3) # 1,取余
print(2 ** 3) # 8,幂运算比较和逻辑:
python
cpu_usage = 85
disk_usage = 70
print(cpu_usage >= 80) # True
print(cpu_usage >= 80 and disk_usage >= 80) # False
print(cpu_usage >= 80 or disk_usage >= 80) # True
print(not cpu_usage >= 80) # False成员判断常用于列表、字符串和字典:
python
services = ["nginx", "mysql", "redis"]
print("nginx" in services) # True
print("php" not in services) # True四、条件判断
if / elif / else 处理分支:
python
cpu_usage = 85
if cpu_usage >= 90:
status = "critical"
elif cpu_usage >= 70:
status = "warning"
else:
status = "ok"
print(f"cpu={cpu_usage}% status={status}")Python 里这些值会被当作 False:
| 值 | 说明 |
|---|---|
0 | 数字零 |
"" | 空字符串 |
[] | 空列表 |
{} | 空字典 |
None | 没有值 |
False | 布尔假 |
示例:
python
result = ""
if not result:
print("result is empty")三元表达式适合很短的判断:
python
level = "high" if cpu_usage >= 80 else "normal"复杂条件写成普通 if 更清楚。脚本不是为了压行数,排查时能一眼看出分支更重要。
五、循环
5.1 for 循环
遍历列表:
python
services = ["nginx", "mysql", "redis"]
for service in services:
print(f"checking {service}")遍历字典:
python
ports = {
"nginx": 80,
"mysql": 3306,
"redis": 6379,
}
for service, port in ports.items():
print(f"{service} -> {port}")带序号遍历:
python
for index, service in enumerate(services, start=1):
print(f"{index}. {service}")range() 生成数字序列:
python
for retry in range(1, 4):
print(f"attempt {retry}")5.2 while 循环
while 适合重试、轮询这类次数不完全固定的逻辑:
python
import time
retry = 0
max_retry = 3
while retry < max_retry:
print(f"attempt={retry + 1}")
retry += 1
time.sleep(1) # 重试之间留一点间隔,避免打满接口或服务5.3 break 和 continue
break 结束整个循环,continue 跳过本次循环。
python
services = ["nginx", "mysql", "redis"]
for service in services:
if service == "mysql":
continue # mysql 交给专门脚本检查
print(f"checking {service}")python
for service in services:
if service == "mysql":
print("found mysql")
break # 找到目标后结束循环六、函数
函数把一段逻辑命名。脚本变长以后,函数能减少重复,也方便单独排查。
python
def format_status(service, status):
# 返回格式统一的状态文本,调用方负责 print 或写日志
return f"service={service} status={status}"
message = format_status("nginx", "ok")
print(message)检查端口示例:
python
import socket
def check_port(host, port, timeout=2):
"""检查 TCP 端口是否能连通。"""
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
try:
result = sock.connect_ex((host, port))
return result == 0
finally:
sock.close() # socket 属于系统资源,用完及时关闭
if check_port("127.0.0.1", 22):
print("ssh is reachable")默认参数:
python
def run_check(name, timeout=30, retries=3):
print(f"name={name} timeout={timeout} retries={retries}")
run_check("disk")
run_check("api", timeout=10)返回多个值时,本质是返回元组:
python
def parse_target(target):
host, port_text = target.split(":")
return host, int(port_text)
host, port = parse_target("127.0.0.1:22")
print(host, port)七、异常处理
异常表示运行时出错。文件不存在、接口超时、字符串转数字失败、命令返回非零,都可能变成异常。脚本里完全不处理异常,失败时只留一大段堆栈;处理过度又会把真正错误吞掉。比较稳的方式是:在边界处捕获,打印清楚上下文,再返回失败退出码。
python
try:
value = int("abc")
except ValueError as exc:
print(f"parse integer failed: {exc}")文件读取:
python
from pathlib import Path
path = Path("/etc/hosts")
try:
content = path.read_text(encoding="utf-8")
except FileNotFoundError:
print(f"file not found: {path}")
else:
print(content.splitlines()[0])finally 适合清理资源:
python
lock_file = open("/tmp/demo.lock", "w", encoding="utf-8")
try:
lock_file.write("running\n")
finally:
lock_file.close() # 不管前面是否报错,都关闭文件句柄主动抛异常:
python
def validate_port(port):
if not 1 <= port <= 65535:
raise ValueError(f"invalid port: {port}")八、退出码
Shell、cron、systemd、CI 都通过退出码判断脚本是否成功。0 表示成功,非零表示失败。
python
import sys
def main():
service_ok = False
if not service_ok:
print("service check failed", file=sys.stderr)
return 1
print("service check ok")
return 0
if __name__ == "__main__":
sys.exit(main())运行后查看退出码:
bash
uv run python check_service.py
echo $?把 main() 写成返回数字,再统一 sys.exit(main()),分支多的时候比到处写 sys.exit() 更清楚。
九、注释和文档字符串
注释写“为什么这样处理”或“这个值有什么背景”,不重复代码本身。
python
# systemd 的 ActiveState 只表示单元状态,不代表 HTTP 接口一定可用
active_state = "active"函数文档字符串写输入、输出和关键限制:
python
def parse_log_line(line):
"""解析一行日志,返回 (time, level, message),格式不匹配时返回 None。"""
parts = line.strip().split(maxsplit=2)
if len(parts) != 3:
return None
return parts[0], parts[1], parts[2]运维脚本常常隔几个月才回头改一次。关键分支、危险操作、外部依赖和退出码位置有注释,后面排查会轻松很多。