尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

个真正能减少重复代码的 Python 标准库

个真正能减少重复代码的 Python 标准库 有着两百行的数据导入脚本, 于这脚本内容当中, 光是路径去执行拼接操作参数会进行校验处理, 添加日志进行打印, 还有文件实施关闭动作, 这几方面就占据了七八十行的篇幅。这样的代码, 其功能不怎么复杂, 然而维护起来却格外麻烦。改动一回目录, 会遗漏两个反斜杠增添一个字段, 初始化逻辑分散于三个位置异常分支一旦增多, close究竟有没有执行都得依靠猜测。当下我着手撰写此种脚本时, 首件事并非去安装第三方包, 而是先行翻阅标准库。接下来所列的这8个, 着实能够削减相当多的重复代码。1. 别再手拼文件路径这种写法我看到就头疼report_file base_dir / day /failed/ batch_no .json嗯Linux之上或许是没什么事儿的, 然而一旦切换到, 那个目录的末尾, 要多出一个斜杠来, 立刻, 就会开始让人感觉别扭了。直接按路径对象处理from pathlib import Path work_dir Path(/data/import) / 2026-07-22 failed_file work_dir / failed / batch_1042.json failed_file.parent.mkdir(parentsTrue, exist_okTrue) failed_file.write_text({status: failed}, encodingutf-8)建构目录, 判别文件, 读取所得内容, 把后缀予以更改这般种种操作, 全部集中于同一个对象之上。在脚本当中, 只要出现三次路径进行拼接的情况, 我通常就会将其替换掉。2. 少写一堆初始化代码输入数据之际, 常常得去界定一个临时的对象。亲手书写, 顿号、逗号, 一旦字段产生变更, 好些地方都会随之变动。from dataclasses import dataclass, field dataclass(slotsTrue) classImportRow: order_no: str amount: int source: str manual errors: list[str] field(default_factorylist) property defvalid(self) - bool: returnnot self.errors在这儿的,需要留意,切忌直接书写 .至于共享可变对象这个陷阱,当代码简短之时反倒更为隐蔽呢。3. 别到处判断 key 存不存在按门店归类失败订单最笨的写法是if shop_code notin failed_orders: failed_orders[shop_code] failed_orders[shop_code].append(order_no)换成 from collections import defaultdict failed_orders defaultdict(list) for row in import_rows: if row.errors: failed_orders[row.source].append(row.order_no)不是存在少两行这般情况的问题, 分支已没有了, 后续增添统计逻辑之际, 不容易出现把初始化写遗漏的状况。在同一个模块以内的, 同样是具备良好使用特性的。针对统计错误的类型而言, 并不需要依靠自身去进行累加器的维护操作:from collections import Counter error_count Counter( error for row in import_rows for error in row.errors )4. 批量处理别重复切片批量写数据库时很多代码都在重复造“分批函数”。for start in range(0, len(records), 500): batch records[start:start 500] save_batch(batch)3.12 可以直接用 . from itertools import batched for batch in batched(records, 500): save_batch(batch)这里, 我会多瞧一下版本, 线上倘若还是旧版本, 那就别为了少几行代码, 偷偷去复制一个同名的实现, 不然后面的人会误以为它就是标准库呢。5. 缓存和函数适配别自己造轮子配置查询, 这类函数, 参数相同, 结果也 same, 还有规则加载, 却在一批数据里反复执行。from functools import lru_cache lru_cache(maxsize256) defload_shop_rule(shop_code: str) - dict: return query_rule_from_db(shop_code)此等缓存适宜于稳定的微小结果, 若返回几十兆的数据, 且内容频繁发生改变, 还往其上面套, 那么这并非是优化, 而是给内存埋下隐患, 是这样的情况, 没错吧。也能处理重复参数from functools import partial write_audit partial( save_event, event_typeorder_import, operatorscheduler ) write_audit(order_noA1024, resultsuccess)6. 资源释放别靠 撑着很多人会写那一层又一层的 try/ , 用于临时切换目录, 用来打开资源, 还要为之加锁。自定义上下文后调用处会干净很多from contextlib import contextmanager from time import perf_counter contextmanager deftrace_cost(task_name: str): started perf_counter try: yield finally: cost perf_counter - started print(f{task_name} cost{cost:.3f}s) with trace_cost(validate-import-file): validate_file(/data/inbox/orders.csv)相较于其他地方, 我更倾向于将计时, 以及锁释放和临时文件清理放置于此。通过这种方式, 业务代码中的缩进少了一层, 在排查异常情况时, 能让人感觉舒服许多。7. 命令行参数不要手撸 sys.argv通常一开始定时脚本有着的是唯独一个参数, 往后日期会被增添, 批次会被增添, 是否重跑也会被增添。持续顺着数组下标去取值, 很快这种东西便会出现:retry sys.argv[3] 1换成 校验和帮助信息一起解决import argparse parser argparse.ArgumentParser parser.add_argument(--day, requiredTrue) parser.add_argument(--batch-size, typeint, default500) parser.add_argument(--retry-failed, actionstore_true) args parser.parse_args参数写错时直接报清楚不用自己维护十几个 if 。8. 别再复制 print 模板刚写脚本来使用时, 运用 print是没有问题的。等到它进入了定时任务之后, 依旧在不断打印“执行成功”这样的字样, 而当出现问题的时候, 基本上是查找不到批次的, 查不到订单号的, 同时也查不到异常栈的。import logging logging.basicConfig( levellogging.INFO, format%(asctime)s %(levelname)s %(message)s ) logger logging.getLogger(order_import) try: imported run_import(args.day, args.batch_size) logger.info(import finished day%s rows%d, args.day, imported) except Exception: logger.exception(import failed day%s, args.day) raise将日志参数写成提前组合成 f-的写法不可取。当日志级别处于关闭状态时, 先计算字符串的情况依旧会发生。少量时难以察觉, 可一旦在循环里打印几万次, 那情况就大不一样了。这八个库, 既谈不上新, 也说不上炫。真正具备实用价值之处, 在于将路径、对象初始化、分组、分批、缓存、资源释放、参数解析以及日志这些处于边缘位置的代码收纳回来。业务代码只剩业务判断脚本才不容易越改越厚。
返回列表