
不知道你有没有遇到过这样的场景每天固定时间打开十几个 Excel把里面的数据复制到一张总表改格式、算汇总然后生成日报发给相关同事。这个过程本身没有什么技术难度但非常消耗精力而且一旦表格数量变多手工操作还容易漏行、复制错列。后来我写了一个 Python 小助手把这类“固定规则 重复操作”的流程变成自动化任务取名叫 WorkBuddy。它做的事情并不复杂定时扫描指定目录里的数据文件自动汇总、计算生成成品报表再把结果通知推送到指定渠道。整个过程中人只需要在后台看结果不再需要手动打开一张张表格。这篇文章我会从需求拆解、环境准备、核心代码、运行验证、常见问题和工程建议几个方面把 WorkBuddy 的完整实现思路分享出来。适合有一定 Python 基础、希望减少重复劳动的开发者和办公自动化需求者也适合想做一个内部小工具的新手入门。读完以后你可以根据自己的业务场景改造成“自己的 WorkBuddy”。1. 背景WorkBuddy 到底在解决什么问题1.1 这些“手动活”的共同特征先看一个具体场景运营部门每天需要统计前一日各渠道的数据数据散落在多个 Excel 文件里每个文件的结构差不多但偶尔会有空白行、格式不一致、列名略有差异。传统做法是一个人每天花 20 到 40 分钟人工复制、粘贴、汇总再手动生成报表。这种工作的特征非常明显规则固定处理逻辑很少变化基本是“读文件 → 清洗 → 合并 → 计算 → 输出”。重复性高每天、每周都要做同样的操作。出错成本高一旦复制错单元格或者漏掉一个文件报表数据就不准确。时间分布散虽然单次时间不长但累积起来很可观。我们常说“DevOps 让部署自动化”其实办公场景里的很多数据整理工作同样可以自动化。自动化的价值不是把简单事情复杂化而是把规则确定、流程固定的事情交给程序去执行。1.2 自动化能带来什么变化把这类任务自动化以后最直接的收益是时间节省。原来每天 30 分钟的整理工作变成脚本运行两三分钟甚至后台静默完成。更重要的是稳定性程序不会因为情绪、疲劳、忙碌而漏操作只要代码逻辑正确每次执行的规则都是一致的。其次自动化任务可以沉淀为一种“资产”。今天写了一个汇总脚本明天业务增加一张表只需要在配置里加一条路径后天需要增加一个新指标只需要在计算逻辑里加几行代码。这个脚本会随着需求演进而被复用而不是每次都从零开始手工处理。最后自动化还带来了可追溯性。人工操作很难回答“上个月某天的报表数据是怎么来的”但代码执行的日志可以记录输入文件、处理时间、计算结果出问题时能快速定位。1.3 WorkBuddy 的定位我们这里说的 WorkBuddy并不是某个商业软件而是一个自制 Python 自动化工具项目。它强调的不是“复杂流程编排”而是“把日常重复任务变得简单可靠”。WorkBuddy 的核心理念可以概括为输入统一所有待处理文件放到指定目录。规则集中处理规则写在代码或配置文件中便于调整。全链路自动化扫描、读取、清洗、计算、输出、通知一条龙完成。有人值守但不手动任务由定时调度触发人只负责查看结果和处理异常。文章后半部分会给出一个贴近真实办公场景的示例代码可以直接复制运行然后根据实际需求修改。2. 需求拆解把任务变成可执行流程在写代码之前先把需求拆开。自动化脚本最难的不是语法而是边界定义不清晰。如果我们说不清楚“输入是什么、输出是什么、中间规则是什么”代码写出来也会很混乱。2.1 一个真实的自动化场景假设现在有这样一个任务某个目录下每天会新增来源不同的 Excel 文件文件名前缀可能不同但都是同一类业务数据。每个 Excel 文件里有一张“明细”工作表包含“日期、渠道、订单量、销售额、退款额”五列。需要汇总所有文件的数据按“日期 渠道”分组计算总订单量、总销售额、总退款额。生成一个汇总后的 Excel 结果文件并附带一个统计报告。任务完成后通过邮件或企业通知把结果发出来。这个场景很典型适合作为 WorkBuddy 的入门案例。下面我们围绕这个案例完成代码设计。2.2 功能模块划分WorkBuddy 的核心模块可以拆成四个部分模块职责对应实现输入模块扫描指定目录筛选符合条件的 Excel 文件定时扫描 路径匹配处理模块读取文件、清洗数据、执行汇总计算pandas 数据处理输出模块生成结果文件、保存日志openpyxl / pandas 写出通知模块将结果推送给相关人员SMTP 邮件 / 企业通知接口这四个模块尽量保持独立。输入模块不需要知道计算逻辑处理模块不关心文件来自哪里通知模块只负责发送消息。这样后续替换任何一个环节都比较方便。2.3 流程设计整个流程可以用下面的简单流程表示待处理目录新增文件 ↓ 定时扫描触发 ↓ 读取所有 Excel 明细 ↓ 数据合并与清洗 ↓ 按日期渠道汇总计算 ↓ 生成结果 Excel 和报告 ↓ 发送通知 ↓ 记录日志这个流程是 WorkBuddy 的主链路。我们实现时会尽量让代码模块化也就是每个功能对应一个函数而不是把所有逻辑堆在一个文件里。3. 环境准备与项目结构3.1 运行环境WorkBuddy 使用 Python 实现代码主要依赖以下库pandas用于读取 Excel、数据处理和汇总统计。openpyxlpandas 读写 Excel 时依赖的引擎。schedule用于实现简单的定时任务调度。版本需要根据你的项目实际情况调整本文示例以常见环境为例重点演示配置思路。建议使用 Python 3.8 或更高版本并创建虚拟环境隔离依赖避免污染系统 Python。在 Windows 上可以直接使用py -m venv venv创建虚拟环境macOS/Linux 上使用python3 -m venv venv。进入虚拟环境后在终端安装依赖。3.2 安装依赖执行下面的命令安装所需库pip install pandas openpyxl schedule如果有特殊网络环境可以把安装源切换为镜像源pip install pandas openpyxl schedule -i https://pypi.tuna.tsinghua.edu.cn/simple安装完成后可以通过以下代码验证关键依赖是否可用import pandas as pd import openpyxl import schedule print(pd.__version__) print(schedule.__version__)如果能正常打印出版本号说明环境没有问题。3.3 目录规划为了提高可维护性建议项目结构如下workbuddy/ ├── config.json # 配置文件 ├── main.py # 主入口负责调度 ├── scanner.py # 文件扫描模块 ├── processor.py # 数据处理模块 ├── reporter.py # 结果输出模块 ├── notifier.py # 通知模块 ├── data/ # 待处理的 Excel 文件目录 │ ├── input/ # 输入目录 │ └── output/ # 输出目录 └── logs/ # 日志目录这不是强制结构但建议保持类似的分层。文件夹一多代码和文件路径如果写死在一起后面会越来越难维护。4. 核心代码实现下面我们逐个模块实现。每个模块都是独立文件最后在main.py中串起来。4.1 配置文件设计WorkBuddy 中输入路径、输出路径、匹配规则、通知参数等都属于“可能变化”的内容建议放在配置文件中而不是写在代码里。创建config.json{ input_dir: data/input, output_dir: data/output, file_pattern: *.xlsx, sheet_name: 明细, required_columns: [日期, 渠道, 订单量, 销售额, 退款额], group_columns: [日期, 渠道], summary_columns: [订单量, 销售额, 退款额], schedule_time: 09:30, notify: { type: smtp, smtp_server: smtp.example.com, smtp_port: 465, sender: senderexample.com, password_env: WORKBUDDY_MAIL_PASSWORD, receivers: [receiverexample.com] } }这里有几个设计上的考虑密码不直接写入配置文件而是通过环境变量引用。配置文件可能会被拷贝、提交到代码仓库里面放明文密码非常危险。file_pattern用通配符匹配文件名方便扩展。required_columns用于读取时校验列的完整性避免某个文件格式不对导致整个任务失败。4.2 文件扫描模块创建scanner.py负责获取指定目录下符合条件的文件列表import json import logging from pathlib import Path logger logging.getLogger(__name__) def load_config(config_pathconfig.json): 加载配置文件 with open(config_path, r, encodingutf-8) as f: return json.load(f) def scan_files(input_dir, pattern): 扫描目录, 返回符合条件的文件路径列表 :param input_dir: 输入目录 :param pattern: 文件名通配符, 例如 *.xlsx :return: Path 对象列表 input_path Path(input_dir) if not input_path.exists(): logger.warning(输入目录不存在: %s, input_path) return [] # glob 匹配模式, 如 *.xlsx files list(input_path.glob(pattern)) # 只保留文件, 排除目录 files [f for f in files if f.is_file()] # 按修改时间排序, 方便排查先后顺序 files.sort(keylambda p: p.stat().st_mtime) logger.info(扫描到 %d 个待处理文件, len(files)) return files这里需要注意一点Path.glob返回的是PosixPath或WindowsPath对象后续处理时可以直接转成字符串传给 pandas。为什么按修改时间排序因为在“批量处理”场景中通常希望按顺序处理文件而且日志里也能看出来处理的先后顺序定位问题更方便。4.3 读取与数据拼接逻辑创建processor.py这是数据处理的核心。import logging import pandas as pd logger logging.getLogger(__name__) def read_excel_file(file_path, sheet_name, required_columns): 读取单个 Excel 文件, 返回标准化后的 DataFrame :param file_path: 文件路径 :param sheet_name: 工作表名称 :param required_columns: 必需列名列表 :return: DataFrame try: df pd.read_excel(file_path, sheet_namesheet_name) except Exception as e: logger.error(读取文件失败: %s, 错误: %s, file_path, e) raise # 检查必需列是否存在 missing_cols [col for col in required_columns if col not in df.columns] if missing_cols: raise ValueError(f文件 {file_path} 缺少列: {missing_cols}) # 只保留需要的列, 避免无关列干扰 df df[required_columns].copy() # 统一日期格式, 先转为字符串再按常见格式解析 df[日期] pd.to_datetime(df[日期], errorscoerce) return df def merge_files(file_paths, sheet_name, required_columns): 读取多个 Excel 文件并纵向拼接 :param file_paths: 文件路径列表 :param sheet_name: 工作表名称 :param required_columns: 必需列名列表 :return: 合并后的 DataFrame df_list [] for file_path in file_paths: logger.info(读取文件: %s, file_path) df_one read_excel_file(file_path, sheet_name, required_columns) df_list.append(df_one) if not df_list: return pd.DataFrame(columnsrequired_columns) df_all pd.concat(df_list, ignore_indexTrue) # 去掉全空白的关键列行 df_all df_all.dropna(subset[日期, 渠道]) return df_all def summary_data(df, group_columns, summary_columns): 按指定列分组, 对指标列求和 :param df: 合并后的 DataFrame :param group_columns: 分组列, 例如 [日期, 渠道] :param summary_columns: 需要求和计算的列 :return: 汇总后的 DataFrame if df.empty: logger.warning(合并后数据为空, 不执行汇总) return df result df.groupby(group_columns, as_indexFalse)[summary_columns].sum() # 将数值列保留两位小数 for col in summary_columns: result[col] result[col].round(2) return result在read_excel_file中我们把日期统一转换为datetime类型。这一步很关键因为不同 Excel 文件里的日期可能有的存成字符串有的存成真正的日期合并前不统一会导致后续分组结果不对。merge_files里的dropna是为了过滤掉空行。很多时候 Excel 里会有一些分隔空行或备注行如果不过滤汇总结果会出现一条 None 分组影响报表观感。4.4 结果输出模块创建reporter.py负责把汇总结果写入 Excel 文件同时生成一个简单的统计说明。import logging from pathlib import Path from datetime import datetime import pandas as pd logger logging.getLogger(__name__) def write_result(result_df, output_dir, prefix汇总): 将汇总结果写入 Excel 文件 :param result_df: 汇总后的 DataFrame :param output_dir: 输出目录 :param prefix: 文件名前缀 :return: 输出文件路径 output_path Path(output_dir) output_path.mkdir(parentsTrue, exist_okTrue) # 文件名带日期, 避免覆盖历史结果 date_str datetime.now().strftime(%Y%m%d_%H%M%S) file_name f{prefix}_{date_str}.xlsx full_path output_path / file_name with pd.ExcelWriter(full_path, engineopenpyxl) as writer: result_df.to_excel(writer, sheet_name汇总结果, indexFalse) logger.info(结果文件已生成: %s, full_path) return str(full_path) def build_report_text(result_df): 根据汇总结果生成一段可读的统计报告文本 :param result_df: 汇总结果 DataFrame :return: 报告字符串 if result_df.empty: return 本次没有读取到有效数据。 total_orders result_df[订单量].sum() total_sales result_df[销售额].sum() total_refund result_df[退款额].sum() date_list result_df[日期].dropna().unique() channel_list result_df[渠道].dropna().unique() lines [ WorkBuddy 自动汇总报告, f统计日期范围: {len(date_list)} 天, f涉及渠道: {len(channel_list)} 个, f汇总订单量: {int(total_orders)}, f汇总销售额: {total_sales:.2f}, f汇总退款额: {total_refund:.2f}, ] return \n.join(lines)输出文件带时间戳是一个很好的习惯。如果直接使用固定文件名每天结果会被覆盖后面想追溯历史数据就做不到了。带时间戳的文件名虽然会多占一点存储空间但排查问题时非常有价值。build_report_text生成的文本可以直接作为邮件正文也可以写到日志里方便快速了解本次处理结果。4.5 通知模块创建notifier.py实现一个简单的 QQ 邮箱 / 企业邮箱通知。这里以 SMTP 为例但请根据实际邮箱服务商调整参数。import os import logging import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart logger logging.getLogger(__name__) def send_mail(config, report_text, attachment_pathNone): 通过 SMTP 发送邮件通知 :param config: 配置文件中的 notify 部分 :param report_text: 邮件正文 :param attachment_path: 附件路径, 可选 smtp_server config[smtp_server] smtp_port config[smtp_port] sender config[sender] receivers config[receivers] # 从环境变量读取密码, 不在配置中存放明文 password os.environ.get(config[password_env], ) if not password: logger.error(未设置环境变量 %s, 跳过邮件发送, config[password_env]) return msg MIMEMultipart() msg[From] sender msg[To] , .join(receivers) msg[Subject] WorkBuddy 自动汇总结果 body MIMEText(report_text, plain, utf-8) msg.attach(body) if attachment_path: from email.mime.application import MIMEApplication file_name attachment_path.split(/)[-1] with open(attachment_path, rb) as f: part MIMEApplication(f.read()) part.add_header( Content-Disposition, attachment, filename(utf-8, , file_name), ) msg.attach(part) try: with smtplib.SMTP_SSL(smtp_server, smtp_port) as server: server.login(sender, password) server.sendmail(sender, receivers, msg.as_string()) logger.info(邮件发送成功) except Exception as e: logger.error(邮件发送失败: %s, e, exc_infoTrue)这里有一个重要的点密码通过环境变量读取。password_env指向环境变量的名字实际使用前需要设置环境变量例如在 Windows 终端中set WORKBUDDY_MAIL_PASSWORDyour_email_password在 Linux/macOS 中export WORKBUDDY_MAIL_PASSWORDyour_email_password真实环境中很多团队使用企业微信机器人、钉钉机器人或飞书机器人通知逻辑是类似的只需要把send_mail替换成对应的 Webhook 推送函数。4.6 定时调度与主入口创建main.py把整个流程串起来并通过schedule实现定时执行。import json import logging import schedule import time from scanner import load_config, scan_files from processor import merge_files, summary_data from reporter import write_result, build_report_text from notifier import send_mail logging.basicConfig( levellogging.INFO, format%(asctime)s [%(levelname)s] %(name)s: %(message)s, handlers[ logging.StreamHandler(), logging.FileHandler(logs/workbuddy.log, encodingutf-8), ], ) logger logging.getLogger(workbuddy) def run_task(): 执行一次完整的 WorkBuddy 任务 logger.info( WorkBuddy 任务开始 ) config load_config() # 1. 扫描文件 files scan_files(config[input_dir], config[file_pattern]) if not files: logger.warning(没有找到待处理文件, 任务结束) return # 2. 读取并合并数据 df_all merge_files( files, sheet_nameconfig[sheet_name], required_columnsconfig[required_columns], ) # 3. 汇总计算 result_df summary_data( df_all, group_columnsconfig[group_columns], summary_columnsconfig[summary_columns], ) # 4. 输出结果 output_file write_result(result_df, config[output_dir]) report_text build_report_text(result_df) # 5. 发送通知 notify_config config.get(notify) if notify_config: send_mail(notify_config, report_text, output_file) logger.info( WorkBuddy 任务结束 ) def main(): 主入口, 启动定时调度 config load_config() schedule_time config.get(schedule_time, 09:30) logger.info(WorkBuddy 已启动, 每天 %s 执行, schedule_time) # 先执行一次, 方便验证 schedule.every().day.at(schedule_time).do(run_task) # 开发调试时可以先手动执行一次 # run_task() while True: schedule.run_pending() time.sleep(1) if __name__ __main__: main()schedule是一个轻量级调度库适合单机场景。它的优点是简单缺点是它只能在程序进程存活时执行调度如果进程退出或电脑关机任务也不会执行。因此在生产环境中更推荐在服务器上使用操作系统的 cronLinux/macOS或 Windows 任务计划程序来定时触发python main.py --once这种模式。你可以在代码里加一个命令行参数来判断是“启动调度”还是“执行一次任务”。5. 运行验证与效果说明5.1 准备测试数据为了验证 WorkBuddy 是否正常工作可以在data/input目录下创建两个测试 Excel 文件。例如data/input/渠道A_20240101.xlsx的“明细”工作表包含日期 渠道 订单量 销售额 退款额 2024-01-01 A 100 5000.00 200.00 2024-01-01 A 150 7500.00 300.00data/input/渠道B_20240101.xlsx的“明细”工作表包含日期 渠道 订单量 销售额 退款额 2024-01-01 B 80 4000.00 100.00 2024-01-01 B 120 6000.00 200.00注意两个文件的 sheet 名称需要是“明细”列名需要和配置中的required_columns保持一致。5.2 执行任务在项目根目录执行python main.py如果你不想等定时调度可以直接把main.py中run_task前面的注释取消脚本一启动就会执行一次同时后台继续进入调度循环。预期输出大致如下2024-01-01 09:30:01 [INFO] workbuddy: WorkBuddy 任务开始 2024-01-01 09:30:01 [INFO] scanner: 扫描到 2 个待处理文件 2024-01-01 09:30:01 [INFO] processor: 读取文件: data/input\渠道A_20240101.xlsx 2024-01-01 09:30:01 [INFO] processor: 读取文件: data/input\渠道B_20240101.xlsx 2024-01-01 09:30:01 [INFO] reporter: 结果文件已生成: data/output\汇总_20240101_093001.xlsx 2024-01-01 09:30:02 [INFO] notifier: 邮件发送成功 2024-01-01 09:30:02 [INFO] workbuddy: WorkBuddy 任务结束 打开data/output目录下生成的 Excel 文件应该可以看到按日期和渠道分组后的汇总数据。由于测试数据日期相同渠道不同最终结果应该有两行一行是渠道 A 的汇总一行是渠道 B 的汇总。5.3 效果说明从上面可以看出WorkBuddy 把“扫描文件 → 读取数据 → 合并清洗 → 汇总计算 → 生成报表 → 发送通知”这一整条链路全部自动化了。业务人员只需把文件放到指定目录每天固定时间就能在邮箱里收到结果。这就是文章标题里“躺着收成品”的意思。不是说什么都不用管而是说规则明确、流程固定的事情不需要人类重复盯着看。6. 常见问题与排查思路在落地过程中可能会遇到一些问题。下面整理几个最常见的场景。问题现象常见原因解决思路扫描不到文件输入目录写错或文件后缀大小写不一致确认目录路径检查file_pattern例如.xlsx和.XLSX读取 Excel 报错pandas 没有安装 openpyxl 引擎或 sheet 名不存在确认sheet_name是否正确重新安装openpyxl中文列名乱码文件编码问题或列名包含空格打印df.columns用 strip 清理列名空格日期分组不对日期列有的是字符串有的是 datetime读取后统一用pd.to_datetime转换邮件发送失败邮箱密码错误、SMTP 服务未开启、环境变量未设置检查password_env是否设置确认邮箱服务商是否开启 SMTP脚本运行完没有日志日志目录不存在或权限不足手动创建logs目录确认程序运行用户有写权限定时任务不触发schedule 使用的时区或系统时间问题检查系统时间或者改用操作系统级定时任务排查问题时建议按这个顺序来先看日志WorkBuddy 会将运行日志输出到控制台和logs/workbuddy.log。大多数问题都能从日志中直接找到原因。再模拟数据准备一个最小可复现的测试文件单独调用对应的处理函数。最后看配置确认config.json里的路径、sheet 名、列名是否和实际文件一致。这里重点提示一个容易忽略的点Excel 文件名有时候是“隐藏后缀”的。比如某个文件名字看起来是数据.xlsx但实际可能是数据.csv。pandas 读取时两种文件的引擎不同所以扫描匹配时一定要确认真实后缀。7. 工程实践建议WorkBuddy 只是一个简化示例真正要把它用到日常工作中还需要注意很多工程细节。7.1 数据安全与备份自动化脚本每天会读取并处理大量数据建议遵循以下原则不要直接修改原始输入文件。WorkBuddy 只读输入目录中的 Excel所有结果输出到另一个目录这样即使处理逻辑出错原始文件也不受影响。输出文件保留时间戳避免覆盖历史结果。定期备份输出目录尤其是数据核对和审计场景。7.2 异常处理和重试机制目前示例中的run_task如果中间报错会直接中断。生产环境中更稳妥的做法是在run_task外层捕获异常并发送告警。每个文件单独处理单个文件出错不影响其他文件。失败任务支持手动重跑可以通过日志判断失败原因。如果任务里包含“读取数据后写入数据库”这样的步骤最好引入幂等性设计也就是同一份数据重复执行不会产生重复记录。常用做法是写入时带唯一键或者先做一次查询判断。7.3 日志规范日志是自动化任务最重要的调试手段。建议做到日志带上时间戳、级别、模块名例如2024-01-01 09:30:01 [INFO] scanner: ...。日志中记录处理文件的数量、生成结果的路径、耗时等关键信息。不要把敏感信息写进日志比如邮箱密码、数据库密码。日志文件可以按天拆分避免单个文件过大。7.4 最小权限原则如果 WorkBuddy 需要操作数据库、调用第三方 API或者访问共享目录应该使用最小权限账号。也就是说这个账号只需要有它职责范围内的权限不需要管理员权限。例如读取数据库时只授予 SELECT 权限写入时只授予对应表的 INSERT 权限调用外部 API 时密钥单独存放到环境变量或密钥管理平台不要写死在代码仓库里。7.5 配置与代码分离不同环境测试、生产的配置可能不同。建议将需要变化的内容都放到config.json代码只负责读取配置。这样更换环境时只需要修改配置文件不需要改动程序逻辑。如果配置项较多还可以考虑引入密钥管理平台例如企业内部配置中心。不过对于个人小工具来说config.json加环境变量已经足够。7.6 任务调度的选择schedule库适合开发调试和轻量场景但它在服务器长期运行时有一些限制进程重启后调度信息丢失。不支持分布式调度。如果需要精确到秒级或分钟级schedule也能做到但维护起来不如系统级 cron 方便。更推荐的方式是写一个单独的run_task入口然后使用 Windows 任务计划程序或 Linux cron 定时调用。例如在 Linux 下配置每天 10 点执行0 10 * * * cd /path/to/workbuddy /usr/bin/python3 main.py --once logs/cron.log 21在 Windows 下可以在任务计划程序中新建一个基本任务设置每天触发操作指向 Python 脚本。这里不再展开具体界面但思路是一样的。8. 后续可以继续深入的方向WorkBuddy 目前只是处理了 Excel 汇总这一种场景但它的模块化设计可以扩展到很多方向把处理结果写入数据库实现报表系统自动更新。集成企业微信机器人/钉钉机器人用 Webhook 替代邮件通知接收更即时。增加文件变化监听使用 watchdog 库实现“文件一放入目录就触发任务”。增加 Web 控制界面通过网页查看历史任务记录和下载结果文件。把任务部署到服务器配合定时调度实现无人值守。如果团队规范允许也可以把它改造成一个可复用的 Python 包通过函数式调用替代命令行调度这样业务系统可以更方便地集成。自动化不是玄学它只不过是把“明确规则”和“定期执行”这两个特征结合起来。每一次减少手动操作都在降低出错概率也是在为更复杂的数据工作流打基础。WorkBuddy 的代码并不复杂真正有价值的是拆解需求、模块化设计和工程化落地的思路。希望这篇笔记能帮你搭建起自己的“收成品”小助手把时间留给更有创造性的事情。