Python 调试技巧:让你的对象不再输出 0x7f...
Python开发中,很多自己造轮子的痛苦,都源于同一个问题:信息差。你以为要手写正则匹配复杂字符串模式,其实 str 自带的方法就能搞定;
你以为调试只能靠 print 大法满天飞,其实标准库里躺着一个低调又强大的调试利器。
1. 用 str.zfill 补零
以前写补零是这样的:
num = 42padded = ('000' + str(num))[-4:]print(padded)
虽然能跑,但读起来完全不知道在干嘛,后来知道有个专门的方法:
num = 42print(str(num).zfill(4)) # '0042'
zfill() 语义清晰,一看就知道在补零。
也可以用 f-string:f'{num:04d}',效果一样。
批量处理编号、生成文件名时特别好用。
2. 用 center/ljust/rjust 对齐文本
做日志或者打表格的时候,我以前这么对齐:
title = 'Hello'padded = ' ' * 10 + title + ' ' * 10print(padded)
手动算空格数,改个标题宽度全乱,其实字符串自带对齐方法:
title = 'Hello'print(title.center(25, '=')) # '==========Hello=========='print(title.ljust(25, '-')) # 'Hello---------------------'print(title.rjust(25, '0')) # '0000000000000000000Hello'
生成表格、对齐日志输出时,这几个方法能省不少事。
3. 用 assert 进行防御性编程
调试的时候我发现一个坏习惯,很多人(包括我)检查参数是这么写的:
def divide(a, b): if b == 0: print('Error: b is 0') # 打印后继续执行... return a / b
问题在于:打印了错误信息,但代码继续往下跑,后面直接崩。
用 assert 更干净:
def divide(a, b): assert b != 0, f'Divisor cannot be zero, got {b}' return a / b
assert 在条件为 False 时直接抛 AssertionError,不会让有问题的代码继续执行。
但注意:python -O 运行时 assert 会被移除,所以别拿它做用户输入校验,它适合做内部假设检查。
4. 用 repr 让对象可调试
以前调试对象状态是这么干的:
class User: def __init__(self, name, age): self.name = name self.age = ageu = User('Alice', 30)print(u) # <__main__.User object at 0x7f...>
啥也看不出来,加个 __repr__ 就好了:
class User: def __init__(self, name, age): self.name = name self.age = age def __repr__(self): return f"User(name='{self.name}', age={self.age})"u = User('Alice', 30)print(u) # User(name='Alice', age=30)
__repr__ 是给开发者看的,理想情况下可以用 eval() 重建对象。
__str__ 是给用户看的,每个类都该有 __repr__,调试时省你半小时。
5. 用 vars() 查看对象属性
想快速看一个对象有哪些属性?别一个个 print 了:
class Config: def __init__(self): self.host = 'localhost' self.port = 8080 self.debug = Truec = Config()print(vars(c))# {'host': 'localhost', 'port': 8080, 'debug': True}
vars(obj) 返回对象的 __dict__,一次性看到所有实例属性。
配合 pprint 效果更好,调试复杂对象时,这是我最常用的一招。
速查表
| 场景 | 别这样写 | 试试这样 |
|---|
| 字符串补零 | ('000' + s)[-4:] | s.zfill(4) 或 f'{n:04d}' |
| 文本对齐 | 手动拼空格 | s.center(25, '=') |
| 参数校验 | if + print 继续跑 | assert condition, msg |
| 打印对象 | <object at 0x...> | 实现 __repr__ |
| 查看属性 | 逐个 print(obj.x) | vars(obj) |
所以别急着造轮子,也别急着否定自己。
多翻翻文档,多看看别人的优雅代码,下次写代码之前先问自己一句:
“这个功能,Python 是不是已经帮我写好了?”
关于作者
写了 10 年 Python,赶上了机器学习的热潮,又撞上了大模型的浪头,每次以为学明白了,行业又变了一次。
把自己踩过的坑、走过的弯路、看过的热闹,说给还在路上的人听。
关注「鲁叶的Python」,第一时间接收技术干货。