Python代码注释三种写法详解:单行、多行与docstring实践
写代码时,注释往往被当作可有可无的东西。但真正维护过项目的人都知道,一段没有注释的代码,隔几个月再回头看,很可能连自己都看不懂。注释不是写给机器看的,而是写给下一个读代码的人——包括未来的你。好的注释能解释代码背后的意图,让维护成本大幅降低。Python提供了三种常用的注释形式,下面逐一说明。一、单行注释:井号
单行注释以 # 开头,从 # 到行尾的内容都会被视为注释,Python解释器会直接忽略。这是最常用、最轻量的注释方式。
# 这是一个单行注释
print('Hello, World!')# 这行打印一句话
# 计算1到100的和
total = 0
for i in range(1, 101):
total += i# 累加每一个数字
print(total)# 输出结果:5050
单行注释还有一个实用场景:临时禁用某一行代码。调试时,把不需要执行的代码注释掉,比删掉再恢复更安全。
print('这条会执行')
# print('这条不会执行,因为被注释掉了')
print('这条也会执行')
在主流IDE中,选中多行后按 Ctrl+(Windows/Linux)或 Cmd+(Mac)可以快速注释或取消注释,配合单行注释调试非常方便。
二、多行注释:三引号
Python没有专门的多行注释语法。一种常见的做法是用三个单引号 ''' 或三个双引号 """ 将内容包裹起来,实现类似多行注释的效果。
'''
这是一个多行注释
可以跨越多行
Python解释器会忽略这些内容
'''
"""
这也是一个多行注释
用双引号也是一样的效果
"""
需要注意的是,三引号包裹的内容本质上是一个字符串字面量,只是它没有被赋值给任何变量,所以解释器创建之后马上丢弃。严格来说,它不是真正的注释,而是“被丢弃的字符串字面量”。但实际开发中,大家都把它当作多行注释使用。
三引号注释常用于三种场景:函数或模块顶部的说明、临时注释掉一大段代码、以及编写文档字符串。
三、文档字符串(docstring)
文档字符串是Python中特殊的“注释”形式,用三引号包裹,写在模块、类或函数的第一行。与普通注释最大的区别是,文档字符串可以被程序动态访问。
def greet(name, greeting='你好'):
'''向指定的人打招呼。
Args:
name: 被问候的人的名字
greeting: 问候语,默认为“你好”
Returns:
str: 完整的问候语字符串
'''
return f'{greeting},{name}!'
# 通过 __doc__ 属性访问文档字符串
print(greet.__doc__)
# 也可以用 help() 查看格式化的文档
help(greet)
有了文档字符串,函数和类的使用者不必阅读实现细节,就能清楚知道参数的格式和返回值。编写自定义函数或类时,花一分钟写一个简短docstring,长期收益很大。
四、什么时候该写注释
不是所有代码都需要注释。判断标准很简单:注释应该解释“为什么”,而不是重复“是什么”。
无意义的注释只会产生噪音:
x = x + 1# 将x加1
有价值的注释解释了原因:
x = x + 1# 补偿索引偏移,因为用户输入的序号从1开始而不是0
以下场景最好写注释:
1. 算法逻辑不直观时。例如埃拉托斯特尼筛法,需要说明为什么只检查到 sqrt(n)。
# 使用埃拉托斯特尼筛法找出所有质数
def sieve_of_eratosthenes(n):
is_prime = * (n + 1)
is_prime = is_prime = False
# 只需检查到sqrt(n),因为如果n是合数,它必定有一个因子小于等于sqrt(n)
for i in range(2, int(n ** 0.5) + 1):
if is_prime:
for j in range(i * i, n + 1, i):
is_prime = False
return ]
2. 函数存在特殊限制或前置条件。比如二分查找要求输入列表已排序,注释可以提醒调用者。
3. 针对特定bug的修复代码。比如为了避免平台差异而使用 os.path.join,这时注释能解释为什么不用硬编码路径。
4. 使用 TODO、FIXME、HACK 标记待办事项或临时方案。
# TODO: 这里的错误处理需要完善,目前只在理想情况下工作
# FIXME: 当用户名为空时会崩溃,需要添加空值检查
# HACK: 这是一个临时方案,等后端接口好了之后要重构
相反,如果代码本身已经很清晰,或者可以通过良好命名表达意图,就不需要额外注释。比如函数名 calculate_average_score,一眼就能看出是计算平均分,不必再加注释。一段复杂逻辑如果能拆分成多个小函数,函数名本身就是最好的注释。
五、注释的黄金法则
核心原则是:注释解释“为什么”,代码说明“是什么”。好的注释能补充代码之外的背景信息,比如业务规则、性能考虑和已知问题。
另一个重要原则是:注释必须与代码保持同步。过时的注释比没有注释更危险,因为它会误导后来的维护者。与其修改注释,不如将逻辑写得更清晰,例如用常量表代替固定税率,代码本身就能说明策略。
关于注释用中文还是英文,取决于场景。个人项目和内部团队项目,用中文沟通成本更低;开源项目或国际化团队,通常用英文;如果项目可能开源,docstring建议中英双语或直接用英文。
六、实战:有注释和无注释的差异
看一个没有注释的函数:
def f(d, p):
r = []
for k, v in d.items():
if p(v):
r.append(k)
return r
data = {'a': 85, 'b': 42, 'c': 96, 'd': 58, 'e': 73}
print(f(data, lambda x: x >= 60))
这个函数干了什么?需要仔细读才能明白。加上良好的命名和注释后:
def filter_by_criteria(data_dict, check_function):
'''根据指定的筛选条件,从字典中筛选出符合条件的键。
参数:
data_dict (dict): 待筛选的字典,键为学生名,值为成绩
check_function (callable): 筛选函数,接受一个值,返回True/False
返回:
list: 符合条件的键(学生名)列表
'''
passed_keys = []# 存储符合条件的学生名
for key, value in data_dict.items():
if check_function(value):
passed_keys.append(key)# 该学生成绩符合条件,加入结果
return passed_keys
# 学生成绩数据
student_scores = {
'小明': 85,
'小红': 42,
'小刚': 96,
'小丽': 58,
'小华': 73
}
# 筛选条件:成绩大于等于60分
def is_passing(score):
return score >= 60
passing_students = filter_by_criteria(student_scores, is_passing)
print(f'及格的学生有:{passing_students}')
print(f'及格人数:{len(passing_students)}人')
print(f'不及格人数:{len(student_scores) - len(passing_students)}人')
虽然行数变多了,但可读性大幅提升,即使换一个人接手也能快速理解逻辑。
七、注释在调试中的妙用
注释也是调试时的利器。当程序出现问题时,可以用单行注释暂时屏蔽部分代码,逐步定位问题。
def complex_calculation(data):
# 第一步:数据清洗
cleaned_data = clean_data(data)
print(f'清洗后数据条数:{len(cleaned_data)}')
# 第二步:怀疑转换有bug,先注释掉后面,只看前面的输出
# transformed_data = transform_data(cleaned_data)
# print(f'转换后数据条数:{len(transformed_data)}')
# 第三步:暂时返回None,等排查完bug再恢复
return None
另外,在学习或实验阶段,可以用注释保留多种实现方式,方便对比和切换:
# 写法一:列表推导式
# squared =
# 写法二:map函数
# squared = list(map(lambda x: x**2, range(10)))
# 写法三:传统for循环,当前采用这种写法,最易读
squared = []
for x in range(10):
squared.append(x ** 2)
print(squared)
八、小结
Python中三种注释形式各有定位:单行注释适合解释局部逻辑;三引号适合多行说明或临时屏蔽代码;docstring则面向工具和API文档,是正规的文档接口。写注释时,多问自己“这里为什么这样写”,而不是“这里写了什么”。好的命名能替代一部分注释,但关键逻辑、业务规则和已知问题,仍然需要注释来记录。保持注释与代码同步,过时的注释应该及时修正或删除。从今天开始,在写代码时把注释当成代码的一部分,长期维护时会受益无穷。
Re: Python代码注释三种写法详解:单行、多行与docstring实践
楼主这篇写得很实在,尤其是“注释是写给下一个读代码的人——包括未来的自己”这句话,深有同感。我前阵子翻自己半年前写的脚本,没注释的地方愣是看了半天才反应过来当初为啥要那么写,加了注释的几段基本一眼就想起当时的思路。 关于三引号当多行注释用,我个人其实习惯直接用 # 逐行注释,因为有些编辑器对三引号高亮处理不一样,万一哪天粗心把它赋值给变量了容易混淆。不过楼主说的“被丢弃的字符串字面量”这个说法很清楚,新手看这个应该能理解本质。 docstring部分讲得也很好,用 help() 和 __doc__ 访问这个点很实用,很多人写函数确实不太习惯开头写一段说明,但团队协作时这个太重要了。还有注释解释“为什么”而不是“是什么”那段,我觉得可以再加个例子:有些时候“是什么”也有价值,比如一些不常见的函数用法,但大概率好命名能解决一大部分问题。 最后提一个小问题:楼主示例里筛法那段代码是不是漏了个类似 `` 的初始化?我看 `is_prime = * (n + 1)` 那地方好像少了点东西,不知道是不是排版原因。总体是篇很实用的小文章,收藏了。Re: Python代码注释三种写法详解:单行、多行与docstring实践
楼主写得很全面,尤其是“注释解释为什么,而不是重复是什么”这个观点,深有体会。我自己就见过很多项目里满屏“将x加1”这种注释,纯粹是噪音,反而把真正有历史背景的说明淹没了。 另外提一个小补充:关于三引号“多行注释”的坑,确实要注意,因为它本质上是个字符串,如果放在代码中间某些位置(比如表达式后面),可能不会像预期那样被忽略,甚至会影响逻辑。我一般会严格要求团队:模块/类/函数文档用docstring,临时屏蔽大段代码尽量用IDE的块注释功能(也就是每行都加#),避免误用三引号。 还有docstring的格式,楼主推荐了Args和Returns风格的描述,很好用。如果要更规范,可以提一下PEP 257或Google风格,不过对普通脚本来说,楼主这种简洁写法已经足够清晰了。Re: Python代码注释三种写法详解:单行、多行与docstring实践
楼主这篇写得很实在,尤其是“注释是写给下一个读代码的人——包括未来的你”这句,深有体会。我自己就吃过没写注释的亏,几个月后看自己的代码跟看天书一样。三种注释的区分讲得清楚,特别是docstring能被程序访问这一点,很多人容易忽略。还有“注释解释为什么,而不是重复是什么”那段,例子给得很直观,感觉可以直接拿来做团队规范参考了。
页:
[1]