Python调试利器:dir和help快速排错

发布时间:2026/8/21 22:09:53
Python调试利器:dir和help快速排错 线上脚本报了个很烦的错AttributeError: OrderClient object has no attribute sync_order遇到这种问题, 我通常不会急着去翻阅文档。特别是那种接手别人编写的包, 其目录里有着众多的类, 还有不少方法名, 并且文档未必能与代码保持同步。与其在那猜测半天, 倒不如先将对象挑出来瞧上一眼。这里就会用到两个老工具 dir 和 help 。dir 干的事很直接把一个对象身上能访问的名字列出来。比如我拿到一个订单客户端对象classOrderClient: def__init__(self, env): self.env env self.timeout 3 defpush_order(self, order_no): 推送订单到外部系统 returnf{order_no} pushed defquery_order(self, order_no): 查询订单状态 return {order_no: order_no, status: WAIT_PAY} client OrderClient(prod) print(dir(client))输出会很长里面有一堆双下划线方法[__class__, __delattr__, __dict__, ..., env, push_order, query_order, timeout]别被这些玩意儿给吓得不行, 你切实需要去瞧的, 通常来讲是后面那几个业务方面的字段以及业务方面的方法。我现场排查时经常会这么过滤一下names [x for x in dir(client) ifnot x.startswith(_)] print(names)输出就清爽多了[env, push_order, query_order, timeout]这当口就一清二楚了, 代码之中所调用的乃是, 对象之上根本就不存在此方法, 仅有的是, 以及。对于这类问题而言, dir的速度要比通过肉眼去翻查代码速度快, 特别是当对象是从第三方的SDK、动态工厂以及配置加载出来的时候, 类在什么地方都不一定能够容易找到, 先进行dir操作一下, 至少能够知晓它当前实实在在的样子。不过 dir 也别迷信。它告知你“有怎样的名字”, 却不告知你“该以怎样的方式去运用这个名字”。比如说, 你瞧见了, 它需要传递几个参数, 要返回什么值, 该如何处理异常, 在dir这里是不管这些的。这时候就该 help 上场了。help(client.push_order)如果代码里 写得还行会看到类似内容push_order(order_no) 推送订单到外部系统帮的作用是将对象的说明信息予以打印呈现出来, 函数能够查看 , 类可以查看 , 模块也能够查看。看函数defclean_mobile(raw): 清洗手机号 - 去掉空格和短横线 - 非 11 位直接返回 None text raw.replace( , ).replace(-, ) if len(text) ! 11: returnNone return text help(clean_mobile)看类help(OrderClient)看模块也行import json help(json)但模块的 help 输出常常是很长的, 我通常不会以这样的方式去看, 除非是在标准库中临时把参数给忘掉了。比如说, 要去处理一批接口日志, 需要将 JSON 字符串转变为字典, 然而突然之间记不清楚 json.loads 以及 json.load 的差异所在, 于是直接:import json help(json.loads) help(json.load)你会发现一个吃字符串一个吃文件对象。与之相比, 去搜索引擎里边翻找半天“json load loads区别”那是较为麻烦的, 远不如这个便捷。特别是在线上机器无法随意访问外网之际, 这两个函数所起到的作用, 基本等同于本地文档, 提供相关信息。再说一个容易踩的点。dir 看到的方法不一定都适合你直接调用。比如这种print([x for x in dir(client) iforderin x])可能输出[push_order, query_order]这个可以参考。但如果输出里有[_build_order_payload, _sign_order_request, push_order]带有下划线的, 日常一般先别去触碰。并非是不能够进行调用, 而是作者在很大概率上是不期望你直接去使用的。那种方法通常情况下是用于在内部拼凑参数、签名以及封装请求的, 要是业务代码直接调用过来, 后续在升级 SDK 的时候就很容易出现故障。我曾目睹有人因贪图省事缘故, 径直进行调用, 彼时的确处于运行成功状态。待过了两周时间之时便有状况发生, 伴随依赖包的一次升级, 字段名称发生改变了, 致使调用方完全失灵皆出现故障。而这责任这可不容易推卸出去呀, 毕竟人家从名字层面就已然对你做出提醒了: 此乃内部一种方法。还有一种情况 dir 看着没问题但调用还是报错。print(push_orderin dir(client)) # True client.push_order结果TypeError: push_order missing 1 required positional argument: order_no这时候别猜参数直接help(client.push_order)或者更硬一点用 看签名import inspect print(inspect.signature(client.push_order))输出(order_no)在排查经过好几层封装的代码之际, 它相当好用。 查看说明借助help, 查看参数依靠. , 明晰名字得用 dir。 将此三者合而为一, 大致能够透彻了解一个对象的差不多七八成 标点。我平时还会写个小函数专门看对象里有哪些能调用的方法defdump_public_methods(obj): rows for name in dir(obj): if name.startswith(_): continue value getattr(obj, name) if callable(value): rows.append(name) return rows print(dump_public_methods(client))输出[push_order, query_order]这段代码构不成复杂的程度, 不过具备显著的实用性。当着手处理一个并不熟悉的对象之际, 首先要去查看它所展现出来的那些公开的方法。千万不要一开始就展开在全局范围内的搜寻工作, 否则你将会被数量众多的具有相同名称的函数、继承而来的类以及用于测试的代码给误导了。help 也有个前提代码作者得写说明。如果函数是这么写的deffix(row): return row那, 即便调用 help(fix) , 对你而言也无济于事。最多能让你知晓存在一个 fix(row) , 然而, 究竟要修复什么内容, 又该以怎样的方式去修复, 却无人能够确切道明(。)。因而在书写之际, 我对于之事的要求并非很高, 然而关键的函数一定要写下两句, 并非是为了呈现出规范的样子, 而是为了三个月过后自己能够少去责骂自己。比如这种就够了defmerge_refund_rows(rows): 合并退款明细。 同一个 refund_no 只保留最后一次状态用于对账导出前的数据压平。 merged {} for row in rows: merged[row[refund_no]] row return list(merged.values)随后其他人进行help()操作, 起码清楚这事物并非随意合并列表, 而是依据退款单号进行覆盖。dir 适合“我不知道它有什么”。help 适合“我知道它有这个东西但不知道怎么用”。有两个函数, 它们既谈不上高级, 也并非新颖, 然而在现场进行排查之时却颇为顺手。存在着诸多问题, 并非是语法困难, 而是对象来回绕动, 让人难以看清。要先将对象展开, 之后再去查看说明, 这比凭借感觉去修改代码可要靠谱得多了。