4、Python基础速通(下):函数定义与参数、文件读写操作、异常处理机制、模块与包管理

好,咱们接着聊。上一节我们把Python的底子打牢了,这一节要讲的东西,才是真正让你从「写脚本」变成「写工具」的关键。

函数、文件、异常、模块——这四个东西,说白了就是Python的「四肢」。你光有语法这个大脑不行,得学会怎么组织代码、怎么跟外部交互、怎么处理意外、怎么复用别人的轮子。我刚开始写自动化脚本那会儿,就是吃了不懂模块化的亏,一个脚本上千行,改个参数得翻半天……嗯,后来才明白,好的代码是「搭积木」,不是「糊水泥」。

Python 基础速通(下) 函数定义与参数 def / 必选/默认/可变参数 文件读写操作 open / with / 编码处理 异常处理机制 try/except/finally/raise 模块与包管理 import / pip / __init__.py 四大核心模块:组织代码 → 读写数据 → 处理异常 → 复用组件

4.1 函数定义与参数:把重复劳动交给机器

函数是什么?说白了就是「把一段逻辑包起来,起个名字,随叫随到」。我个人的习惯是:只要一段代码出现两次以上,我就把它写成函数。别嫌麻烦,这是运维脚本的命根子。

4.1.1 基本定义与调用

Python用def关键字定义函数,简单直接。你想想看,没有函数的世界多可怕——每次都要把同样的逻辑写一遍,改一个地方得改所有地方。

def check_disk_usage(threshold=80):
    """检查磁盘使用率,超过阈值返回告警"""
    import psutil
    usage = psutil.disk_usage('/').percent
    if usage > threshold:
        return f"告警:磁盘使用率已达 {usage}%"
    return f"正常:当前使用率 {usage}%"
💡 我的习惯:函数一定要写文档字符串(就是那个三引号里的内容)。别偷懒,三个月后你自己都看不懂当初写的逻辑。

4.1.2 参数类型详解

Python的参数系统很灵活,但也容易让人迷糊。我把它分成四类,你记住就行:

参数类型 写法示例 说明
必选参数 def func(a, b) 调用时必须按顺序传入
默认参数 def func(a, b=10) 不传就用默认值,传了就覆盖
可变参数 def func(*args) 接收任意多个参数,打包成元组
关键字参数 def func(**kwargs) 接收任意多个key=value,打包成字典

举个例子,我在写日志收集脚本时经常这么用:

def log_collector(server_ip, *ports, **options):
    print(f"目标服务器:{server_ip}")
    print(f"监控端口:{ports}")
    if options.get('timeout'):
        print(f"超时设置:{options['timeout']}秒")
    # 实际逻辑省略...

# 调用方式很灵活
log_collector('192.168.1.100', 80, 443, 3306, timeout=30)
⚠️ 避坑指南:默认参数不要用可变对象(比如空列表[])!我曾经因为这个坑排查了整整一下午——多个调用共享同一个列表,数据全乱了。正确做法是用None,然后在函数内部判断。

4.2 文件读写操作:和操作系统打交道

运维脚本最常干的事是什么?读日志、写配置、处理数据。文件操作就是你的「手」,得用得溜。

4.2.1 打开文件的正确姿势

Python内置的open()函数是基础,但我强烈建议你用with语句。为什么?因为with会自动帮你关闭文件,不用操心资源泄漏的问题。

# 不推荐的方式(容易忘关文件)
f = open('/var/log/syslog', 'r')
content = f.read()
f.close()  # 万一这行忘了呢?

# 推荐的方式(自动关闭)
with open('/var/log/syslog', 'r', encoding='utf-8') as f:
    content = f.read()
# 出了with块,文件自动关闭

4.2.2 读写模式一览

模式这东西,记不住没关系,记住常用的几个就行:

  • 'r' — 只读模式,文件必须存在
  • 'w' — 写入模式,文件存在则覆盖,不存在则创建
  • 'a' — 追加模式,在文件末尾添加内容
  • 'rb' / 'wb' — 二进制模式,处理图片、压缩包等

重点来了:处理文本文件时,一定要指定encoding参数。我遇到过太多次因为编码问题导致的乱码事故了。Linux下默认UTF-8,Windows下可能是GBK,你不指定,脚本换个环境就崩。

4.2.3 实战:逐行读取大文件

运维日志动不动就几个G,你敢用read()一次性读完?内存直接爆炸。正确的做法是逐行读取:

def grep_log(log_path, keyword):
    """在日志文件中搜索关键字,返回匹配行"""
    matches = []
    with open(log_path, 'r', encoding='utf-8') as f:
        for line in f:  # 逐行读取,不占内存
            if keyword in line:
                matches.append(line.strip())
    return matches

# 使用示例
result = grep_log('/var/log/nginx/access.log', '500')
print(f"找到 {len(result)} 条500错误")

4.3 异常处理机制:让脚本学会「扛揍」

脚本跑着跑着突然崩了,这种事你肯定遇到过。异常处理就是给你的脚本穿上「防弹衣」——不是不让它出错,而是出错后能优雅地处理,而不是直接崩溃。

4.3.1 try-except 的基本结构

Python的异常处理很直观:你试着干一件事,如果出错了,就按你指定的方式处理。

try:
    # 可能会出错的代码
    result = 10 / 0
except ZeroDivisionError:
    # 捕获特定异常
    print("除数不能为0!")
except Exception as e:
    # 捕获其他所有异常(但不推荐滥用)
    print(f"发生了未知错误:{e}")
else:
    # 没有异常时执行
    print("计算成功")
finally:
    # 不管有没有异常,都会执行
    print("清理工作完成")
💡 我的经验:不要用裸的except:捕获所有异常。你想想看,连键盘中断(Ctrl+C)都被你吞了,想停都停不下来。至少要写成except Exception as e,把错误信息打印出来。

4.3.2 自定义异常与主动抛出

有时候你需要主动告诉调用者:「这里出问题了」。用raise就可以:

class ConfigError(Exception):
    """自定义配置异常"""
    pass

def load_config(file_path):
    if not os.path.exists(file_path):
        raise ConfigError(f"配置文件 {file_path} 不存在")
    # 正常加载逻辑...

我曾经写过一个自动化部署脚本,就是因为没有做异常处理,结果某次配置文件格式错了,脚本直接崩溃,导致线上服务中断了10分钟……从那以后,我每条可能出错的代码都加了try-except。

4.4 模块与包管理:站在巨人的肩膀上

Python最强大的地方之一,就是它的生态。你不需要重复造轮子,别人已经写好了各种功能模块,你直接拿来用就行。

4.4.1 import 的几种方式

导入模块,说白了就是告诉Python:「我要用这个工具箱」。方式有几种:

# 方式1:导入整个模块
import os
print(os.getcwd())

# 方式2:导入特定函数(推荐,减少命名冲突)
from os import getcwd, listdir
print(getcwd())

# 方式3:起别名(处理长名字)
import pandas as pd
import numpy as np

# 方式4:导入所有(不推荐,容易覆盖变量)
# from os import *  # 慎用!

4.4.2 包的结构与创建

当你的脚本越来越多,就需要用「包」来组织。包其实就是一个包含__init__.py文件的目录:

my_tools/                  # 这是一个包
    __init__.py            # 包初始化文件(可以为空)
    network.py             # 网络相关函数
    disk.py                # 磁盘相关函数
    log_utils.py           # 日志工具函数

然后在其他脚本中就可以这样导入:

from my_tools.network import check_port
from my_tools.disk import get_disk_usage

4.4.3 pip 包管理

安装第三方库,用pip就够了。我个人建议你养成一个好习惯:每个项目都创建虚拟环境,避免包版本冲突。

# 创建虚拟环境
python -m venv myenv

# 激活虚拟环境(Linux/Mac)
source myenv/bin/activate

# 激活虚拟环境(Windows)
myenv\Scripts\activate

# 安装包
pip install requests paramiko

# 导出依赖清单
pip freeze > requirements.txt

# 别人拿到项目后一键安装
pip install -r requirements.txt

核心原则:永远不要在全局环境里装包!我见过太多人因为全局环境混乱,导致不同项目依赖冲突,最后只能重装Python。虚拟环境就是你的「隔离沙箱」,每个项目各玩各的,互不干扰。

小结

这一节的内容,说白了就是让你从「写单行脚本」升级到「写可维护的工具」。函数让代码可复用,文件操作让脚本能读写数据,异常处理让脚本更健壮,模块管理让代码更清晰。

我个人觉得,这四个技能里,最容易被忽视的是异常处理。很多新手觉得「我的脚本不会出错」,但现实是——网络会断、磁盘会满、配置文件会格式错误。给脚本穿上防弹衣,是对自己负责,也是对线上环境负责。

📌 一句话总结:函数是骨架,文件是血肉,异常是铠甲,模块是武器——四者结合,你就能写出真正能上生产环境的自动化脚本。


公众号:蓝海资料掘金营,微信deep3321