找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4325

积分

0

好友

572

主题
发表于 2 小时前 | 查看: 1| 回复: 0

代码里一旦开始出现 for i in range(len(xxx))、两层 if 套着判断、拿 lambda 硬拧排序,我基本就知道这段代码还能再收一收。

Python 真有些东西,用的时候不觉得,回头看旧代码会嫌弃自己:当时怎么能写那么笨。下面这 6 个内置函数,我是真觉得顺手,而且不是那种“面试题式顺手”,是你改脚本、清数据、写接口兜底、查日志时,会很自然掏出来的那种。

1. enumerate:别再自己维护下标了

我最烦这种代码:

rows = ["A100", "A101", "A102"]
i = 0

for row in rows:
    print(f"第{i+1}行: {row}")
    i += 1

这东西不是不能跑,就是别扭。循环的是数据,脑子里还得分一块地方去记索引,纯属给自己找事。直接上 enumerate

rows = ["A100", "A101", "A102"]

for line_no, row in enumerate(rows, start=1):
    print(f"第{line_no}行: {row}")

做导入校验时尤其顺手,报错定位非常直接:

def validate_users(rows):
    errors = []

    for line_no, row in enumerate(rows, start=2):  # Excel表头占一行
        mobile = row.get("mobile")
        name = row.get("name")

        if not mobile:
            errors.append(f"第{line_no}行手机号为空")
            continue

        if len(name or "") > 20:
            errors.append(f"第{line_no}行姓名长度超过20")

    return errors

这种地方你要是还手动 index += 1,我第一眼就不太信这代码后面能写多利索。

2. zip:两份数据要并着走,别自己凑

线上对账、字段比对、批量拼装参数,这类场景经常会有两份列表一起处理。很多人会这么写:

user_ids = [101, 102, 103]
scores = [88, 92, 76]

for i in range(len(user_ids)):
    print(user_ids[i], scores[i])

问题不大,就是土。zip 的意思很直接:你俩绑一块走。

user_ids = [101, 102, 103]
scores = [88, 92, 76]

for user_id, score in zip(user_ids, scores):
    print(user_id, score)

做批量入库参数整理时很好用:

order_ids = [9001, 9002, 9003]
statuses = ["paid", "cancelled", "paid"]

payload = []
for order_id, status in zip(order_ids, statuses):
    payload.append({
        "order_id": order_id,
        "status": status
    })

再往前一步,字典都能直接拼,在处理 CSV 或接口字段映射时能极大提升开发效率

fields = ["name", "mobile", "dept"]
values = ["张三", "13800000000", "技术部"]

user = dict(zip(fields, values))
print(user)
# {'name': '张三', 'mobile': '13800000000', 'dept': '技术部'}

有个细节要记一下:zip 默认按最短的来。也就是说两边长度不一致,多出来的那部分会被静默扔掉。所以我自己遇到核心数据拼装,通常会先看一眼长度:

if len(order_ids) != len(statuses):
    raise ValueError(“订单ID和状态数量不一致”)

这种坑,晚发现不如早一点嫌弃它。

3. any:只要有一个满足,立刻停

这个函数特别适合“拦截式判断”。比如你拿到一批导入数据,想先看看有没有空手机号。很多人会先写个标志位:

has_empty_mobile = False

for row in rows:
    if not row.get("mobile"):
        has_empty_mobile = True
        break

这就有点 Java 后遗症了。Python 里直接写:

has_empty_mobile = any(not row.get("mobile") for row in rows)

看着就干净。接口结果聚合时也常用。比如调用下游多个节点,只要有一个失败就告警:

results = [
    {"host": "10.0.0.1", "ok": True},
    {"host": "10.0.0.2", "ok": True},
    {"host": "10.0.0.3", "ok": False},
]

if any(not item["ok"] for item in results):
    print("有节点执行失败,先别往下走”)

日志关键字扫描也顺手:

keywords = ["TimeoutError", "Connection refused", "BrokenPipeError"]

if any(word in log_text for word in keywords):
    print(“这段日志值得单独拎出来看”)

我平时看异常日志,第一步经常不是通读全文,而是先看有没有几个眼熟的坏味道。any 就特别适合干这个。

4. all:不是“有没有”,是“是不是全都满足”

allany 正好反过来。比如你批量校验接口参数,要求每条数据都带 user_id

if all(item.get(“user_id”) for item in payload):
    print(“参数完整,可以发请求”)
else:
    print(“有脏数据,别发”)

或者校验一组文件是不是都存在:

from pathlib import Path

files = [
    "/data/task/a.csv",
    "/data/task/b.csv",
    "/data/task/c.csv",
]

if all(Path(f).exists() for f in files):
    print(“依赖文件齐了”)

这个在定时任务里很常见。有些脚本启动前必须确认几份输入文件、几项配置、几个环境变量都在,不然跑一半才炸,最恶心。再比如检查返回码是不是都成功:

resp_list = [
    {"code": 0, "msg": "ok"},
    {"code": 0, "msg": "ok"},
    {"code": 0, "msg": "ok"},
]

if all(resp["code"] == 0 for resp in resp_list):
    print(“全部成功”)

这种写法一眼就知道你在干嘛,不需要读两层循环才明白意图。

5. sorted:排序别只会升序降序,key 才是正经东西

很多人用 sorted 只会写个:

nums = [5, 2, 9, 1]
print(sorted(nums))

这当然没毛病,但也没啥意思。真正在线上脚本里常用的是 key。你想按哪个字段排、按什么规则排,全在这里。比如日志按耗时倒排,先把最慢的接口揪出来:

api_logs = [
    {"path": "/order/create", "cost_ms": 120},
    {"path": "/user/detail", "cost_ms": 45},
    {"path": "/pay/callback", "cost_ms": 860},
]

slow_logs = sorted(api_logs, key=lambda x: x[“cost_ms”], reverse=True)
print(slow_logs)

输出以后,谁慢一眼就看见了。再比如批量处理文件时,按修改时间排:

from pathlib import Path

files = list(Path("/data/export").glob("*.csv"))
files = sorted(files, key=lambda x: x.stat().st_mtime, reverse=True)

for f in files[:5]:
    print(f.name)

还有个我自己挺常用的写法:排序时把空值扔最后面。

users = [
    {"name": "张三", "score": 90},
    {"name": "李四", "score": None},
    {"name": "王五", "score": 85},
]

users = sorted(users, key=lambda x: (x["score"] is None, x["score"]))
print(users)

这个 (x[“score”] is None, x[“score”]) 看着有点绕,但真好使。业务里很多字段不是每条都有,直接排经常会炸或者顺序很怪,这种小技巧能省你一次排查。

6. getattr:动态取属性的时候,比 if-else 铺满地强太多

这玩意很多人知道,但用得不多。一旦开始写一些通用导出、动态排序、对象字段兜底,它就很顺手。比如你有个对象列表,想按传入字段排序:

class Job:
    def __init__(self, job_id, status, retry_count):
        self.job_id = job_id
        self.status = status
        self.retry_count = retry_count

jobs = [
    Job(1, "running", 2),
    Job(2, "failed", 5),
    Job(3, “success”, 0),
]

sort_field = “retry_count”
jobs = sorted(jobs, key=lambda x: getattr(x, sort_field, 0), reverse=True)

for job in jobs:
    print(job.job_id, job.retry_count)

再比如做字段兜底:

class User:
    def __init__(self, name, mobile=None):
        self.name = name
        self.mobile = mobile

u = User(“张三”)

mobile = getattr(u, “mobile”, “”)
dept = getattr(u, “dept”, “未知部门”)

print(mobile, dept)

你要是不用 getattr,很多时候就会开始写这种代码:

if hasattr(u, “dept”):
    dept = u.dept
else:
    dept = “未知部门”

不是不能写,就是看着累。还有一种比较实战的场景:接口适配。老系统、新系统返回对象字段不一致,先兜底取值:

def pick_display_name(obj):
    return (
        getattr(obj, “nickname”, None)
        or getattr(obj, “real_name”, None)
        or getattr(obj, “username”, “”)
    )

这个在对接历史包袱系统时真能少写很多烂判断。

以上就是六个在实战中能显著提升代码整洁度和Python开发效率的内置函数。它们不是什么高深莫测的黑魔法,而是在日常的数据处理、脚本编写和接口开发中,能让你思路更清晰、代码更短小的实用工具。多在实际场景里想想“有没有更省力的写法”,代码质量自然就上去了。如果想了解更多实战技巧和深入交流,欢迎访问云栈社区




上一篇:从离职同事返岗尴尬场面,聊聊算法面试中的动态规划思路
下一篇:技术人群需警惕:心源性猝死并非突然,这6类高危人群请自查
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-3-26 21:21 , Processed in 0.789597 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表