文章目录

P.S. 目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。

前言

兄弟们,先问个扎心的问题:你写Python代码多少年了?是不是天天在IDE里点运行按钮,把文件路径、模型参数、处理阈值全写死在代码里,结果一到要把脚本发给同事用,或者要放到服务器跑定时任务,别人一改参数就得改源码,当场社死?是不是见过大佬的Python脚本一行命令就能传各种配置,跑不同的业务逻辑,自己却连sys.argv是啥都搞不清,只会对着代码里的硬编码改来改去,改一次跑一次?

我在AI行业摸爬滚打了22年,见过太多写了3-5年Python的开发者,甚至包括不少天天写AI算法、自动化脚本的老哥,代码写得丝滑流畅,结果一到要做脚本化、工具化就抓瞎。明明一个sys.argv就能搞定的事,非要让用户去改源码里的路径和参数,最后不是用户改坏了代码跑不起来,就是线上环境因为硬编码的路径出了生产事故。

更离谱的是,很多新手一上来就为了处理两个参数,去装click、fire这些第三方库,甚至搞一套复杂的参数解析框架,结果脚本发给别人,人家一运行就报ModuleNotFoundError,连第一步都跑不起来。完全忘了Python原生就给我们提供了零依赖、全平台兼容、所有版本都能用的命令行参数解决方案——sys.argv。

这篇文章,我就用最通俗的段子和类比,从零到一带你吃透sys.argv,从基础用法到高频踩坑,再到2026年AI开发、自动化场景的实战案例,看完你就能写出不用改源码、一行命令就能跑的专业Python脚本。哪怕你是刚学Python的高中生,也能看懂、能上手。

一、先搞懂:sys.argv到底是个啥?为啥你一定要学?

1.1 先掰明白:什么是命令行参数?

很多新手一听到“命令行参数”就头大,觉得是什么高大上的底层技术,其实说白了,它就跟你点外卖时的备注要求一模一样。

你打开终端敲python xxx.py,这就相当于你打开外卖APP,选好了商家和主品(也就是你的Python脚本);而你在后面加的python xxx.py 123 abc /home/data,这些空格隔开的内容,就是你给脚本传的“备注要求”,也就是命令行参数。

平时你在IDE里写死参数,就像你每次点外卖,都要重新填一遍收货地址、口味、加不加料,每次改需求都要重新编辑整个订单;而用命令行参数,就像你把订单模板做好了,每次下单只需要改几个核心选项,完全不用动模板本身——也就是不用改你的Python源码。

可能有兄弟会说:我就在IDE里跑脚本,不用命令行,学这个有啥用?

我只能说,2026年了,AI时代都来了,你写的代码总不能永远只在自己电脑上跑吧?

  • 你写了个AI图片批量推理脚本,要发给同事用,总不能让人家连Python都没搞懂,就去改你源码里的模型路径、输入文件夹吧?
  • 你写了个数据处理脚本,要放到服务器上跑定时任务,总不能每次改个日期范围,都要登服务器改源码吧?
  • 你写了个小工具,要开源给网友用,总不能让每个人都去改代码里的硬编码,最后全来给你提issue说跑不起来吧?

而sys.argv,就是解决这些问题的最优解——零依赖、全平台兼容、简单到极致,只要装了Python就能用,不用额外装任何库,走到哪都能跑。

1.2 sys.argv的本质:就是个普通Python列表,没什么神秘的

很多新手把sys.argv想的太复杂,其实它本质上就是Python给你内置好的一个普通列表(list),没有任何花里胡哨的黑魔法。你只要会用Python的列表,就会用sys.argv。

这个列表里的内容,规则简单到离谱:

  1. 列表的第一个元素(索引0),永远是你当前运行的脚本本身的名字(或者你敲的脚本路径)
  2. 列表里从第二个元素(索引1)开始,就是你在命令行里敲的、用空格分隔的所有参数
  3. 不管你敲的是数字、字母、路径,所有内容进了sys.argv,全都会变成字符串类型

我给你举个最简单的例子,你一眼就能懂。

我们新建一个Python文件,名字叫test.py,里面只写三行代码:

# 先导入sys模块,就像你进小区要先刷门禁卡
import sys
# 直接打印sys.argv这个列表
print("sys.argv的内容是:", sys.argv)
# 打印它的类型,给你看看是不是真的是列表
print("sys.argv的类型是:", type(sys.argv))

现在我们打开终端,运行这个脚本,看看会发生什么。

场景1:只运行脚本,不传任何参数

命令:python test.py
输出结果:

sys.argv的内容是: ['test.py']
sys.argv的类型是: <class 'list'>

你看,没有传任何参数的时候,sys.argv里只有一个元素,就是脚本名test.py

场景2:运行脚本,传多个参数

命令:python test.py hello 123 3.14 /home/ai/data
输出结果:

sys.argv的内容是: ['test.py', 'hello', '123', '3.14', '/home/ai/data']
sys.argv的类型是: <class 'list'>

看到了吗?你在命令行里用空格隔开的每一段内容,都按顺序变成了sys.argv列表里的元素,哪怕你敲的是数字123、3.14,进了列表也全变成了字符串。

这里我给你打个比方,就像你去奶茶店点单,你对着店员喊:“奶茶 三分糖 加珍珠 少冰”。店员手里的订单本,第一行永远是你点的主品“奶茶”,后面的每一行,就是你提的要求,不管你说的是数字“三分糖”还是文字“加珍珠”,店员都会先统一记成文字,回头再给后厨转成对应的操作——就像你后面要把字符串转成int、float类型一样。

就这么简单,sys.argv没有任何神秘的地方,它就是个存了脚本名和命令行参数的列表,你会操作列表,就会用它。

二、从零到一:sys.argv的基础用法,看完就能上手

2.1 第一步:先搞对导入,别上来就踩坑

我见过太多新手,上来就直接写print(argv),然后运行就报NameError: name 'argv' is not defined,当场懵了,以为自己Python环境坏了。

其实原因特别简单:argv是sys模块里的属性,你必须先导入sys模块,才能用sys.argv,不能直接用argv。

这就像你想进小区拿快递,必须先刷门禁卡(import sys),不然你连小区门都进不去,更别说拿快递(用argv)了。很多新手上来就直接对着小区里喊“快递给我”,保安直接给你拦下来了,可不就报错了嘛。

正确的写法,永远是先在脚本最顶部导入sys:

import sys
# 后面才能用sys.argv

2.2 第二步:正确取值,索引别搞反了

前面我们说了,sys.argv[0]永远是脚本名,你真正要拿的用户参数,是从sys.argv[1] 开始的!这个点,80%的新手第一次用都会搞反。

我给你举个最常见的例子:写一个脚本,接收两个数字,输出它们的和。

新手常写的错误代码:
import sys
# 错误1:取了索引0,拿到的是脚本名,不是参数
a = sys.argv[0]
b = sys.argv[1]
# 错误2:没有转类型,直接相加,变成了字符串拼接
print(a + b)

你运行python sum.py 1 2,猜猜输出什么?结果是sum.py1,当场傻眼。为啥?因为你取了sys.argv[0]的脚本名,而且两个字符串相加,就是拼接在一起,根本不是数字求和。

正确的写法,要避开这两个核心坑:
import sys

# 先判断有没有传够参数,避免索引越界,新手必加
if len(sys.argv) < 3:
    print("用法:python sum.py 数字1 数字2")
    print("示例:python sum.py 1 2")
    # 参数不对,直接优雅退出,不往下执行
    sys.exit()

# 正确取值:从索引1开始,并且转成数字类型
a = float(sys.argv[1])
b = float(sys.argv[2])

# 计算并输出结果
print(f"两个数的和是:{a + b}")

我们运行这个脚本,看看效果:

  • 正确传参:python sum.py 10 20,输出两个数的和是:30.0
  • 没传够参数:python sum.py 10,会输出用法提示,不会直接报错崩溃
  • 传了非数字:python sum.py abc 20,会报类型错误,这个我们后面会讲怎么处理

这个正确的例子里,有三个你必须记住的核心要点,少一个都容易出问题:

  1. 索引从1开始取参数,0永远是脚本名,别搞错
  2. 必须先判断参数个数,不然用户没传够参数,直接取sys.argv[1]会报IndexError: list index out of range,脚本直接崩了
  3. 必须做类型转换,sys.argv里的所有元素都是字符串,要做数字计算,必须转成int或者float,不然就是字符串拼接

2.3 基础场景实战:3个日常工作最常用的例子,拿来就能用

光说不练假把式,我给你整理了3个2026年程序员、AI开发者日常工作里最常用的场景,全是sys.argv就能搞定的,代码拿来就能改、就能用。

场景1:批量修改文件后缀名脚本

做AI数据处理、文件管理的兄弟,肯定经常遇到这种需求:把一个文件夹里的所有.jpg改成.jpeg,或者把.txt改成.csv,总不能一个个手动改吧?用这个脚本,一行命令搞定,不用改源码。

import sys
import os

# 先判断参数个数
if len(sys.argv) < 4:
    print("用法:python rename.py 目标目录 原后缀 新后缀")
    print("示例:python rename.py /home/ai/data jpg jpeg")
    sys.exit()

# 从命令行获取参数
target_dir = sys.argv[1]
old_suffix = sys.argv[2].lstrip(".")  # 去掉用户可能加的.
new_suffix = sys.argv[3].lstrip(".")

# 判断目录是否存在
if not os.path.isdir(target_dir):
    print(f"错误:目录 {target_dir} 不存在")
    sys.exit(1)

# 遍历目录里的所有文件
count = 0
for filename in os.listdir(target_dir):
    # 匹配原后缀的文件
    if filename.endswith(f".{old_suffix}"):
        # 拼接完整路径
        old_path = os.path.join(target_dir, filename)
        # 生成新文件名
        new_filename = filename.replace(f".{old_suffix}", f".{new_suffix}")
        new_path = os.path.join(target_dir, new_filename)
        # 重命名
        os.rename(old_path, new_path)
        count += 1
        print(f"已修改:{filename} -> {new_filename}")

print(f"操作完成,共修改了 {count} 个文件")

运行方式:python rename.py ./data jpg png,就能把data文件夹里所有的.jpg文件改成.png,不用改一行代码,换目录、换后缀直接改命令行参数就行。

场景2:AI批量推理脚本

2026年了,大家都玩大模型、图像识别、AI绘图,写个推理脚本,总不能每次换个模型、换个输入文件夹都改代码吧?用sys.argv传参数,一行命令搞定,发给同事直接就能用。

import sys
import os
import cv2
import numpy as np
# 这里用onnxruntime做推理,主流AI推理框架
import onnxruntime as ort

if len(sys.argv) < 4:
    print("用法:python infer.py 模型路径 输入图片文件夹 输出结果文件夹")
    print("示例:python infer.py ./models/face_recog.onnx ./input_imgs ./output_result")
    sys.exit()

# 从命令行获取参数
model_path = sys.argv[1]
input_dir = sys.argv[2]
output_dir = sys.argv[3]

# 校验模型文件
if not os.path.exists(model_path):
    print(f"错误:模型文件 {model_path} 不存在")
    sys.exit(1)

# 校验输入目录
if not os.path.isdir(input_dir):
    print(f"错误:输入目录 {input_dir} 不存在")
    sys.exit(1)

# 创建输出目录
if not os.path.exists(output_dir):
    os.makedirs(output_dir)

# 加载模型
session = ort.InferenceSession(model_path)
input_name = session.get_inputs()[0].name
input_shape = session.get_inputs()[0].shape
print(f"模型加载成功,输入要求:{input_shape}")

# 批量处理图片
img_suffix = ["jpg", "jpeg", "png", "bmp"]
count = 0
for filename in os.listdir(input_dir):
    # 过滤图片文件
    if filename.split(".")[-1].lower() not in img_suffix:
        continue
    # 读取图片
    img_path = os.path.join(input_dir, filename)
    img = cv2.imread(img_path)
    if img is None:
        print(f"警告:无法读取图片 {filename},已跳过")
        continue
    # 预处理:resize到模型要求的尺寸,归一化
    h, w = input_shape[2], input_shape[3]
    img_resize = cv2.resize(img, (w, h))
    img_input = img_resize.transpose(2, 0, 1)[np.newaxis, :, :, :].astype(np.float32) / 255.0
    # 推理
    result = session.run(None, {input_name: img_input})
    # 保存结果
    output_path = os.path.join(output_dir, f"{filename.split('.')[0]}_result.npy")
    np.save(output_path, result)
    count += 1
    print(f"已处理:{filename},结果已保存")

print(f"推理完成,共处理了 {count} 张图片")

这个脚本,你发给同事,同事不用改你一行代码,只要把自己的模型路径、输入输出文件夹传进去就能跑,这不比你让同事改源码里的路径香?还不会出现同事改坏代码的情况。

场景3:定时任务日志脚本

服务器上跑定时任务,最常用的就是日志脚本,用sys.argv传日志级别和保存路径,不用每次改定时任务的代码,直接改命令行参数就行。

import sys
import os
from datetime import datetime

if len(sys.argv) < 3:
    print("用法:python task_log.py 日志级别 日志保存路径")
    print("示例:python task_log.py info /var/log/ai_daily_task.log")
    sys.exit()

# 从命令行获取参数
log_level = sys.argv[1].lower()
log_path = sys.argv[2]

# 日志级别映射
level_map = {
    "debug": 0,
    "info": 1,
    "warn": 2,
    "error": 3
}
if log_level not in level_map:
    print(f"错误:不支持的日志级别 {log_level},支持的级别:debug/info/warn/error")
    sys.exit(1)

# 创建日志目录
log_dir = os.path.dirname(log_path)
if log_dir and not os.path.exists(log_dir):
    os.makedirs(log_dir)

# 写日志的函数
def write_log(level, content):
    if level_map[level] >= level_map[log_level]:
        time_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log_line = f"[{time_str}] [{level.upper()}] {content}\n"
        # 追加写入日志文件
        with open(log_path, "a", encoding="utf-8") as f:
            f.write(log_line)
        # 同时打印到控制台
        print(log_line, end="")

# 这里写你的定时任务逻辑
write_log("info", "每日AI数据同步任务开始执行")
try:
    # 模拟任务执行
    write_log("debug", "正在连接数据库")
    write_log("debug", "正在拉取今日新增数据")
    write_log("info", "今日共拉取1256条新数据")
    write_log("debug", "正在清洗数据")
    write_log("debug", "正在写入AI训练库")
    write_log("info", "任务执行成功")
except Exception as e:
    write_log("error", f"任务执行失败:{str(e)}")
    sys.exit(1)

运行方式:python task_log.py debug ./task.log,就能输出debug级别的所有日志;如果是线上正式跑,就用python task_log.py info ./task.log,只输出info及以上级别的日志,不用改一行代码,直接在定时任务里改命令行参数就行。

三、90%的人都会踩的sys.argv坑,我帮你全踩过了,别再掉进去

我搞了22年开发,见过太多人,哪怕是工作了好几年的老手,都栽在这些sys.argv的基础坑里,轻则脚本跑不起来,重则线上出生产事故。今天我把这些坑全给你列出来,讲清楚怎么踩的、怎么避免,看完你就能少走90%的弯路。

3.1 天坑一号:忘了参数全是字符串,不做类型转换

这个是90%的新手第一次用都会踩的坑,没有之一。

前面我们反复强调,sys.argv里的所有元素,不管你敲的是数字还是字母,全都是字符串类型。很多新手忘了这一点,直接拿参数做数字运算、大小比较,结果要么直接报错,要么出现离谱的结果。

踩坑示例1:直接做数字比较,报错
import sys
age = sys.argv[1]
# 直接拿字符串和数字比较,直接报TypeError
if age > 18:
    print("成年了")
else:
    print("未成年")

运行python age.py 20,直接报错:TypeError: '>' not supported between instances of 'str' and 'int',当场懵了。

踩坑示例2:隐蔽的字符串比较,结果完全错误

这个坑更离谱,很多老手都偶尔会踩。比如你写个脚本比较两个数字的大小:

import sys
a = sys.argv[1]
b = sys.argv[2]
if a > b:
    print(f"{a}{b} 大")
else:
    print(f"{a}{b} 小")

你运行python compare.py 100 20,猜猜输出什么?结果是100 比 20 小

是不是离谱到家了?为啥?因为字符串的比较,是按每个字符的ASCII码来比的,"100"的第一个字符是’1’,ASCII码是49;“20"的第一个字符是’2’,ASCII码是50。49 < 50,所以字符串"100” < “20”,结果就完全错了。

避坑方案:

只要是数字类型的参数,必须先转成int或者float,再做运算和比较。就像你去超市买东西,店员扫条码,必须把条码的字符串转成商品的价格数字,才能算总价,不能直接拿条码字符串去算钱。

正确写法:

import sys
if len(sys.argv) < 3:
    print("用法:python compare.py 数字1 数字2")
    sys.exit()
# 先转成数字类型
a = float(sys.argv[1])
b = float(sys.argv[2])
if a > b:
    print(f"{a}{b} 大")
else:
    print(f"{a}{b} 小")

3.2 天坑二号:不判断参数个数,直接索引取值,导致索引越界

新手最常写的代码,就是上来直接a = sys.argv[1],完全不判断用户有没有传这个参数。结果用户运行的时候,少传了一个参数,直接报IndexError: list index out of range,脚本直接崩了。

尤其是线上跑定时任务的时候,参数少传了一个,任务直接崩了,你查日志都要查半天,才发现是这么个低级错误。

踩坑示例:
import sys
# 直接取值,不判断有没有参数
input_path = sys.argv[1]
output_path = sys.argv[2]
print(f"从{input_path}读取数据,保存到{output_path}")

用户运行python task.py ./input,只传了一个参数,直接报错索引越界,脚本崩溃。

避坑方案:

必须先判断len(sys.argv)的长度,够不够你需要的参数个数。不够的话,给用户提示正确的用法,然后用sys.exit()优雅退出,绝对不能直接取值。

就像你去餐厅吃饭,服务员先看你点的菜够不够下锅,你只点了个火锅底料,没点菜,服务员肯定会提醒你,而不是直接给你上一锅开水。

3.3 天坑三号:参数里有空格,没加引号,导致参数被拆分

这个坑,很多老手都偶尔会踩,尤其是Windows用户,路径里经常有空格,比如C:\Users\AI 教程\data,结果一运行就报错路径不存在,找半天找不到原因。

踩坑示例:

你写了个脚本,接收一个路径参数:

import sys
import os
if len(sys.argv) < 2:
    print("用法:python check_path.py 路径")
    sys.exit()
path = sys.argv[1]
print(f"你输入的路径是:{path}")
print(f"路径是否存在:{os.path.exists(path)}")

你运行python check_path.py C:\Users\AI 教程\data,结果输出:

你输入的路径是:C:\Users\AI
路径是否存在:False

为啥?因为sys.argv是按空格拆分参数的,你带空格的路径,被拆成了两个参数,sys.argv[1]C:\Users\AIsys.argv[2]教程\data,路径自然就不对了。

避坑方案:

带空格的参数,必须用双引号(Windows)或者单引号(Linux/Mac)包起来

正确的运行命令:python check_path.py "C:\Users\AI 教程\data",这样sys.argv就会把整个引号里的内容当成一个元素,不会拆分,路径就正确了。

就像你点外卖,备注里有一句话“多放辣,不要香菜,谢谢”,你必须把这句话写在同一个备注框里,不能拆成好几条,不然商家就会当成好几个要求,给你做错。

3.4 天坑四号:以为sys.argv[0]是绝对路径,结果获取脚本路径出错

很多新手以为sys.argv[0]是脚本的绝对路径,其实根本不是。sys.argv[0]的值,完全取决于你运行脚本的时候,敲的是什么路径。

比如你的脚本在/home/ai/script.py

  • 你在/home/ai/目录下,运行python script.py,sys.argv[0]就是script.py(只有文件名,没有路径)
  • 你运行python /home/ai/script.py,sys.argv[0]就是/home/ai/script.py(完整绝对路径)
  • 你在/home/目录下,运行python ai/script.py,sys.argv[0]就是ai/script.py(相对路径)

很多新手用sys.argv[0]去拼接脚本所在目录的其他文件,结果换个目录运行脚本,就报错找不到文件。

避坑方案:

如果你要获取脚本的绝对路径,或者脚本所在的目录,必须用os.path模块做处理,不能直接用sys.argv[0]。

正确写法:

import sys
import os

# 获取脚本的绝对路径
script_abs_path = os.path.abspath(sys.argv[0])
# 获取脚本所在的目录
script_dir = os.path.dirname(script_abs_path)

print(f"脚本绝对路径:{script_abs_path}")
print(f"脚本所在目录:{script_dir}")

这样不管你在哪个目录运行脚本,都能正确获取到脚本的绝对路径和所在目录,不会出错。

四、sys.argv的进阶用法:不止是传参数,这些技巧能让你的脚本更专业

4.1 处理不定数量的参数:传多少接多少,不用固定个数

很多时候,我们不知道用户会传多少个参数,比如要写个脚本,计算任意多个数字的和,不管用户传1个还是100个数字,都能算。这时候就可以用列表切片sys.argv[1:],把除了脚本名之外的所有参数都拿出来,灵活处理。

完整示例:任意多个数字求和脚本
import sys

# 拿到所有用户传入的参数,排除脚本名
args = sys.argv[1:]

# 判断有没有传参数
if not args:
    print("用法:python sum_all.py 数字1 数字2 数字3 ...")
    print("示例:python sum_all.py 1 2 3 4 5")
    sys.exit(1)

# 遍历参数,转成数字求和,加异常处理
total = 0
valid_count = 0
for arg in args:
    try:
        # 尝试转成浮点数
        num = float(arg)
        total += num
        valid_count += 1
    except ValueError:
        # 转失败了,给出警告,跳过
        print(f"警告:【{arg}】不是有效的数字,已跳过")

# 输出结果
print(f"有效数字个数:{valid_count}")
print(f"所有有效数字的和是:{total}")

这个脚本,你传多少个数字都能算,比如:

  • 运行python sum_all.py 1 2 3 4 5,输出和为15
  • 运行python sum_all.py 10 20 abc 30,会警告abc不是有效数字,输出和为60
  • 哪怕你传100个数字,也能正常计算,不用改一行代码

就像你去奶茶店,不管你加多少种小料,店员都能给你算总价,不会因为你加的多就不会算了。

4.2 配合sys.exit(),用退出码告诉上级脚本执行结果

前面我们多次用到了sys.exit(),很多新手只知道它能退出脚本,却不知道它还能传退出码,这个功能在Linux定时任务、shell脚本、自动化流程里特别有用。

sys.exit()的规则:

  • sys.exit(0):代表脚本正常执行成功退出
  • sys.exit(非0数字):代表脚本异常退出,不同的数字可以代表不同的错误类型

比如,我们可以规定:

  • 退出码1:参数个数不对
  • 退出码2:输入路径不存在
  • 退出码3:模型文件加载失败

这样,你的上级shell脚本,就能根据退出码,判断你的Python脚本有没有跑成功,失败的原因是什么,从而做对应的处理,比如失败了发告警、重试等。

示例:带规范退出码的脚本
import sys
import os

if len(sys.argv) < 3:
    print("用法:python process.py 输入目录 模型文件")
    # 参数错误,退出码1
    sys.exit(1)

input_dir = sys.argv[1]
model_path = sys.argv[2]

if not os.path.isdir(input_dir):
    print(f"错误:输入目录 {input_dir} 不存在")
    # 路径不存在,退出码2
    sys.exit(2)

if not os.path.exists(model_path):
    print(f"错误:模型文件 {model_path} 不存在")
    # 模型不存在,退出码3
    sys.exit(3)

# 这里写业务逻辑
print("所有校验通过,开始执行任务...")
# 任务执行成功
print("任务执行完成")
sys.exit(0)

4.3 什么时候用sys.argv?什么时候用argparse?

很多新手会问:Python还有个argparse标准库,也是处理命令行参数的,还有第三方的click、fire,我该用哪个?

这里我给你讲的明明白白,不用纠结:

特性 sys.argv argparse 第三方库(click/fire)
依赖 零依赖,原生自带 零依赖,原生自带 需要安装第三方库
复杂度 极简,5分钟学会 中等,需要学习参数配置 有学习成本,需要看文档
帮助文档 需要自己写 自动生成–help帮助文档 自动生成帮助文档
适用场景 简单参数、小脚本、快速原型 多参数、带选项、正式工具 复杂命令行工具、开源项目

说白了,sys.argv就像你家门口的便利店,买瓶水、买包烟,快速方便,不用走流程;argparse就像大超市,东西全,品类多,适合买很多东西,但是要走入口、结账,流程多一点;第三方库就像大型商场,啥都有,但是你得专门开车过去,还要找停车位。

2026年了,很多新手上来就装一堆第三方库,处理个简单的两个参数,非要用click、fire,其实完全没必要。sys.argv就能搞定的事,零依赖,脚本发给别人,直接就能跑,不用让用户先装一堆库,这不香吗?

只有当你的脚本参数很多,有很多可选选项,需要给用户提供完善的帮助文档,做正式的工具的时候,再用argparse或者第三方库。

五、2026年实战案例:用sys.argv写一个AI训练数据预处理脚本,拿来就能用

最后,我给你一个完整的、2026年AI开发里天天都能用到的实战脚本——AI图像训练数据批量预处理脚本。做计算机视觉的兄弟都知道,训练模型前,必须把所有图片统一resize、归一化、格式转换,这个脚本用sys.argv传所有参数,不用改一行代码,一行命令就能跑。

import sys
import os
import cv2
import numpy as np
from tqdm import tqdm

def main():
    # 校验参数个数
    if len(sys.argv) < 6:
        print("="*50)
        print("AI训练数据批量预处理脚本")
        print("用法:python preprocess.py 输入目录 输出目录 目标宽度 目标高度 图片格式")
        print("示例:python preprocess.py ./raw_imgs ./train_imgs 640 640 jpg")
        print("参数说明:")
        print("  输入目录:原始图片所在的文件夹")
        print("  输出目录:预处理后图片保存的文件夹")
        print("  目标宽度:resize后的图片宽度")
        print("  目标高度:resize后的图片高度")
        print("  图片格式:输出的图片格式,支持jpg/png/bmp")
        print("="*50)
        sys.exit(1)

    # 从命令行获取所有参数
    input_dir = sys.argv[1]
    output_dir = sys.argv[2]
    try:
        target_w = int(sys.argv[3])
        target_h = int(sys.argv[4])
    except ValueError:
        print("错误:目标宽度和高度必须是整数")
        sys.exit(1)
    output_format = sys.argv[5].lower()

    # 校验参数合法性
    if target_w <= 0 or target_h <= 0:
        print("错误:目标宽度和高度必须大于0")
        sys.exit(1)
    if output_format not in ["jpg", "png", "bmp"]:
        print(f"错误:不支持的输出格式 {output_format},支持的格式:jpg/png/bmp")
        sys.exit(1)
    if not os.path.isdir(input_dir):
        print(f"错误:输入目录 {input_dir} 不存在")
        sys.exit(1)

    # 创建输出目录
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
        print(f"提示:已创建输出目录 {output_dir}")

    # 支持的图片后缀
    support_suffix = ["jpg", "jpeg", "png", "bmp", "tiff"]
    # 遍历输入目录,获取所有图片
    img_list = []
    for filename in os.listdir(input_dir):
        suffix = filename.split(".")[-1].lower()
        if suffix in support_suffix:
            img_list.append(filename)

    if not img_list:
        print(f"警告:输入目录 {input_dir} 里没有找到支持的图片")
        sys.exit(0)

    print(f"找到 {len(img_list)} 张图片,开始预处理...")
    print(f"目标尺寸:{target_w}x{target_h},输出格式:{output_format}")

    # 批量处理图片,带进度条
    success_count = 0
    fail_count = 0
    for filename in tqdm(img_list, desc="预处理进度"):
        try:
            # 读取图片
            img_path = os.path.join(input_dir, filename)
            img = cv2.imread(img_path, cv2.IMREAD_COLOR)
            if img is None:
                print(f"警告:无法读取图片 {filename},已跳过")
                fail_count += 1
                continue

            # 等比例resize,保持宽高比,填充黑边
            h, w = img.shape[:2]
            # 计算缩放比例
            scale = min(target_w / w, target_h / h)
            new_w = int(w * scale)
            new_h = int(h * scale)
            # 缩放图片
            img_resize = cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_AREA)
            # 创建目标尺寸的黑底画布
            canvas = np.zeros((target_h, target_w, 3), dtype=np.uint8)
            # 把缩放后的图片放到画布中间
            x_offset = (target_w - new_w) // 2
            y_offset = (target_h - new_h) // 2
            canvas[y_offset:y_offset+new_h, x_offset:x_offset+new_w, :] = img_resize

            # 生成输出文件名
            output_filename = f"{filename.split('.')[0]}.{output_format}"
            output_path = os.path.join(output_dir, output_filename)
            # 保存图片
            if output_format == "jpg":
                cv2.imwrite(output_path, canvas, [cv2.IMWRITE_JPEG_QUALITY, 95])
            else:
                cv2.imwrite(output_path, canvas)

            success_count += 1
        except Exception as e:
            print(f"错误:处理图片 {filename} 失败,原因:{str(e)}")
            fail_count += 1

    # 输出处理结果
    print("="*50)
    print("预处理完成!")
    print(f"成功处理:{success_count} 张")
    print(f"处理失败:{fail_count} 张")
    print(f"处理后的图片已保存到:{output_dir}")
    print("="*50)

if __name__ == "__main__":
    main()

这个脚本,是我平时做AI项目天天用的,功能非常完善:

  1. 等比例resize,保持图片宽高比,不会拉伸变形,填充黑边
  2. 支持多种输入图片格式,输出格式可指定
  3. 带进度条,能看到处理进度
  4. 完善的异常处理,单张图片处理失败不会影响整个脚本
  5. 所有参数全从命令行传入,不用改一行代码

运行方式也特别简单,比如:
python preprocess.py ./raw_data ./train_data 640 640 jpg
就能把raw_data里的所有图片,统一处理成640x640的jpg图片,保存到train_data里。

你可以根据自己的需求,修改里面的预处理逻辑,比如改成批量灰度化、批量归一化、批量加水印,都可以,参数还是用sys.argv传,非常灵活。

P.S. 目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。

更多推荐