查看: 33|回复: 3

Python代码注释三种写法详解:单行、多行与docstring实践

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
写代码时,注释往往被当作可有可无的东西。但真正维护过项目的人都知道,一段没有注释的代码,隔几个月再回头看,很可能连自己都看不懂。注释不是写给机器看的,而是写给下一个读代码的人——包括未来的你。好的注释能解释代码背后的意图,让维护成本大幅降低。Python提供了三种常用的注释形式,下面逐一说明。

一、单行注释:井号

单行注释以 # 开头,从 # 到行尾的内容都会被视为注释,Python解释器会直接忽略。这是最常用、最轻量的注释方式。
  1. # 这是一个单行注释
  2. print('Hello, World!')  # 这行打印一句话
  3. # 计算1到100的和
  4. total = 0
  5. for i in range(1, 101):
  6.     total += i  # 累加每一个数字
  7. print(total)  # 输出结果:5050
复制代码

单行注释还有一个实用场景:临时禁用某一行代码。调试时,把不需要执行的代码注释掉,比删掉再恢复更安全。
  1. print('这条会执行')
  2. # print('这条不会执行,因为被注释掉了')
  3. print('这条也会执行')
复制代码

在主流IDE中,选中多行后按 Ctrl+(Windows/Linux)或 Cmd+(Mac)可以快速注释或取消注释,配合单行注释调试非常方便。

二、多行注释:三引号

Python没有专门的多行注释语法。一种常见的做法是用三个单引号 ''' 或三个双引号 """ 将内容包裹起来,实现类似多行注释的效果。
  1. '''
  2. 这是一个多行注释
  3. 可以跨越多行
  4. Python解释器会忽略这些内容
  5. '''
  6. """
  7. 这也是一个多行注释
  8. 用双引号也是一样的效果
  9. """
复制代码

需要注意的是,三引号包裹的内容本质上是一个字符串字面量,只是它没有被赋值给任何变量,所以解释器创建之后马上丢弃。严格来说,它不是真正的注释,而是“被丢弃的字符串字面量”。但实际开发中,大家都把它当作多行注释使用。

三引号注释常用于三种场景:函数或模块顶部的说明、临时注释掉一大段代码、以及编写文档字符串。

三、文档字符串(docstring)

文档字符串是Python中特殊的“注释”形式,用三引号包裹,写在模块、类或函数的第一行。与普通注释最大的区别是,文档字符串可以被程序动态访问。
  1. def greet(name, greeting='你好'):
  2.     '''向指定的人打招呼。
  3.     Args:
  4.         name: 被问候的人的名字
  5.         greeting: 问候语,默认为“你好”
  6.     Returns:
  7.         str: 完整的问候语字符串
  8.     '''
  9.     return f'{greeting},{name}!'
  10. # 通过 __doc__ 属性访问文档字符串
  11. print(greet.__doc__)
  12. # 也可以用 help() 查看格式化的文档
  13. help(greet)
复制代码

有了文档字符串,函数和类的使用者不必阅读实现细节,就能清楚知道参数的格式和返回值。编写自定义函数或类时,花一分钟写一个简短docstring,长期收益很大。

四、什么时候该写注释

不是所有代码都需要注释。判断标准很简单:注释应该解释“为什么”,而不是重复“是什么”。

无意义的注释只会产生噪音:
  1. x = x + 1  # 将x加1
复制代码

有价值的注释解释了原因:
  1. x = x + 1  # 补偿索引偏移,因为用户输入的序号从1开始而不是0
复制代码

以下场景最好写注释:

1. 算法逻辑不直观时。例如埃拉托斯特尼筛法,需要说明为什么只检查到 sqrt(n)。
  1. # 使用埃拉托斯特尼筛法找出所有质数
  2. def sieve_of_eratosthenes(n):
  3.     is_prime = [True] * (n + 1)
  4.     is_prime[0] = is_prime[1] = False
  5.     # 只需检查到sqrt(n),因为如果n是合数,它必定有一个因子小于等于sqrt(n)
  6.     for i in range(2, int(n ** 0.5) + 1):
  7.         if is_prime[i]:
  8.             for j in range(i * i, n + 1, i):
  9.                 is_prime[j] = False
  10.     return [i for i in range(2, n + 1) if is_prime[i]]
复制代码

2. 函数存在特殊限制或前置条件。比如二分查找要求输入列表已排序,注释可以提醒调用者。

3. 针对特定bug的修复代码。比如为了避免平台差异而使用 os.path.join,这时注释能解释为什么不用硬编码路径。

4. 使用 TODO、FIXME、HACK 标记待办事项或临时方案。
  1. # TODO: 这里的错误处理需要完善,目前只在理想情况下工作
  2. # FIXME: 当用户名为空时会崩溃,需要添加空值检查
  3. # HACK: 这是一个临时方案,等后端接口好了之后要重构
复制代码

相反,如果代码本身已经很清晰,或者可以通过良好命名表达意图,就不需要额外注释。比如函数名 calculate_average_score,一眼就能看出是计算平均分,不必再加注释。一段复杂逻辑如果能拆分成多个小函数,函数名本身就是最好的注释。

五、注释的黄金法则

核心原则是:注释解释“为什么”,代码说明“是什么”。好的注释能补充代码之外的背景信息,比如业务规则、性能考虑和已知问题。

另一个重要原则是:注释必须与代码保持同步。过时的注释比没有注释更危险,因为它会误导后来的维护者。与其修改注释,不如将逻辑写得更清晰,例如用常量表代替固定税率,代码本身就能说明策略。

关于注释用中文还是英文,取决于场景。个人项目和内部团队项目,用中文沟通成本更低;开源项目或国际化团队,通常用英文;如果项目可能开源,docstring建议中英双语或直接用英文。

六、实战:有注释和无注释的差异

看一个没有注释的函数:
  1. def f(d, p):
  2.     r = []
  3.     for k, v in d.items():
  4.         if p(v):
  5.             r.append(k)
  6.     return r
  7. data = {'a': 85, 'b': 42, 'c': 96, 'd': 58, 'e': 73}
  8. print(f(data, lambda x: x >= 60))
复制代码

这个函数干了什么?需要仔细读才能明白。加上良好的命名和注释后:
  1. def filter_by_criteria(data_dict, check_function):
  2.     '''根据指定的筛选条件,从字典中筛选出符合条件的键。
  3.     参数:
  4.         data_dict (dict): 待筛选的字典,键为学生名,值为成绩
  5.         check_function (callable): 筛选函数,接受一个值,返回True/False
  6.     返回:
  7.         list: 符合条件的键(学生名)列表
  8.     '''
  9.     passed_keys = []  # 存储符合条件的学生名
  10.     for key, value in data_dict.items():
  11.         if check_function(value):
  12.             passed_keys.append(key)  # 该学生成绩符合条件,加入结果
  13.     return passed_keys
  14. # 学生成绩数据
  15. student_scores = {
  16.     '小明': 85,
  17.     '小红': 42,
  18.     '小刚': 96,
  19.     '小丽': 58,
  20.     '小华': 73
  21. }
  22. # 筛选条件:成绩大于等于60分
  23. def is_passing(score):
  24.     return score >= 60
  25. passing_students = filter_by_criteria(student_scores, is_passing)
  26. print(f'及格的学生有:{passing_students}')
  27. print(f'及格人数:{len(passing_students)}人')
  28. print(f'不及格人数:{len(student_scores) - len(passing_students)}人')
复制代码

虽然行数变多了,但可读性大幅提升,即使换一个人接手也能快速理解逻辑。

七、注释在调试中的妙用

注释也是调试时的利器。当程序出现问题时,可以用单行注释暂时屏蔽部分代码,逐步定位问题。
  1. def complex_calculation(data):
  2.     # 第一步:数据清洗
  3.     cleaned_data = clean_data(data)
  4.     print(f'清洗后数据条数:{len(cleaned_data)}')
  5.     # 第二步:怀疑转换有bug,先注释掉后面,只看前面的输出
  6.     # transformed_data = transform_data(cleaned_data)
  7.     # print(f'转换后数据条数:{len(transformed_data)}')
  8.     # 第三步:暂时返回None,等排查完bug再恢复
  9.     return None
复制代码

另外,在学习或实验阶段,可以用注释保留多种实现方式,方便对比和切换:
  1. # 写法一:列表推导式
  2. # squared = [x**2 for x in range(10)]
  3. # 写法二:map函数
  4. # squared = list(map(lambda x: x**2, range(10)))
  5. # 写法三:传统for循环,当前采用这种写法,最易读
  6. squared = []
  7. for x in range(10):
  8.     squared.append(x ** 2)
  9. print(squared)
复制代码

八、小结

Python中三种注释形式各有定位:单行注释适合解释局部逻辑;三引号适合多行说明或临时屏蔽代码;docstring则面向工具和API文档,是正规的文档接口。写注释时,多问自己“这里为什么这样写”,而不是“这里写了什么”。好的命名能替代一部分注释,但关键逻辑、业务规则和已知问题,仍然需要注释来记录。保持注释与代码同步,过时的注释应该及时修正或删除。从今天开始,在写代码时把注释当成代码的一部分,长期维护时会受益无穷。
回复

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Python代码注释三种写法详解:单行、多行与docstring实践

楼主这篇写得很实在,尤其是“注释是写给下一个读代码的人——包括未来的自己”这句话,深有同感。我前阵子翻自己半年前写的脚本,没注释的地方愣是看了半天才反应过来当初为啥要那么写,加了注释的几段基本一眼就想起当时的思路。 关于三引号当多行注释用,我个人其实习惯直接用 # 逐行注释,因为有些编辑器对三引号高亮处理不一样,万一哪天粗心把它赋值给变量了容易混淆。不过楼主说的“被丢弃的字符串字面量”这个说法很清楚,新手看这个应该能理解本质。 docstring部分讲得也很好,用 help() 和 __doc__ 访问这个点很实用,很多人写函数确实不太习惯开头写一段说明,但团队协作时这个太重要了。还有注释解释“为什么”而不是“是什么”那段,我觉得可以再加个例子:有些时候“是什么”也有价值,比如一些不常见的函数用法,但大概率好命名能解决一大部分问题。 最后提一个小问题:楼主示例里筛法那段代码是不是漏了个类似 `` 的初始化?我看 `is_prime = * (n + 1)` 那地方好像少了点东西,不知道是不是排版原因。总体是篇很实用的小文章,收藏了。
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Python代码注释三种写法详解:单行、多行与docstring实践

楼主写得很全面,尤其是“注释解释为什么,而不是重复是什么”这个观点,深有体会。我自己就见过很多项目里满屏“将x加1”这种注释,纯粹是噪音,反而把真正有历史背景的说明淹没了。 另外提一个小补充:关于三引号“多行注释”的坑,确实要注意,因为它本质上是个字符串,如果放在代码中间某些位置(比如表达式后面),可能不会像预期那样被忽略,甚至会影响逻辑。我一般会严格要求团队:模块/类/函数文档用docstring,临时屏蔽大段代码尽量用IDE的块注释功能(也就是每行都加#),避免误用三引号。 还有docstring的格式,楼主推荐了Args和Returns风格的描述,很好用。如果要更规范,可以提一下PEP 257或Google风格,不过对普通脚本来说,楼主这种简洁写法已经足够清晰了。
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Python代码注释三种写法详解:单行、多行与docstring实践

楼主这篇写得很实在,尤其是“注释是写给下一个读代码的人——包括未来的你”这句,深有体会。我自己就吃过没写注释的亏,几个月后看自己的代码跟看天书一样。三种注释的区分讲得清楚,特别是docstring能被程序访问这一点,很多人容易忽略。还有“注释解释为什么,而不是重复是什么”那段,例子给得很直观,感觉可以直接拿来做团队规范参考了。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-8-25 15:17 , Processed in 0.023011 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部