Python入门:Python代码注释的三种写法详解
Python入门:Python代码注释的三种写法详解
一、开篇:好代码需要好注释
在上一篇文章中,我们写出了第一行Python代码。今天我们要聊一个看似简单、但很多程序员做了很多年都没做好的话题:代码注释。
📝 注释是写在代码里、但不被Python执行的一段文字。它的作用是给读代码的人(包括未来的你自己)解释代码的含义、逻辑和注意事项。
你可能觉得"我写的代码我自己能看懂,不需要注释"。相信我,三个月后回来看你今天写的代码,如果没有注释,你大概率会对着屏幕发呆:“这代码到底是谁写的?”——是你自己写的,但你已经忘了当时的思路。
💡 一个编程高手的标志之一,就是能写出恰到好处的注释。不是越多越好,也不是越少越好,而是"刚好解释清楚为什么这样写"。
二、Python的三种注释方式
Python提供了三种写注释的方式,每种都有自己的用途。
2.1 单行注释:井号
这是最常用的注释方式。以#开头,#之后直到行尾的所有内容都是注释。
# 这是一个单行注释print('Hello, World!')# 这行打印一句话,这也是注释# 下面这行代码计算1到100的和total=0foriinrange(1,101):total+=i# 累加每一个数字print(total)# 输出结果:5050单行注释也可以用来临时禁用某一行代码(调试时特别常用):
print('这条会执行')# print('这条不会执行,因为被注释掉了')print('这条也会执行')⌨️ 绝大多数IDE中,选中几行代码然后按Ctrl + /(Mac:Cmd + /)可以快速注释/取消注释。
2.2 多行注释:三个引号
用三个单引号'''或三个双引号"""包裹起来的内容,可以作为多行注释。
''' 这是一个多行注释 可以跨越多行 Python解释器会忽略这些内容 '''""" 这也是一个多行注释 用双引号也是一样的效果 可以写很多行 """⚠️ 技术细节:三个引号在Python中实际上创建了一个字符串对象,只是这个字符串没有被赋值给任何变量,所以Python创建了它之后马上丢弃。因此严格来说这不是"注释",而是一个"被丢弃的字符串字面量"。但在实际使用中,大家都把它当作多行注释来用。
三种引号的使用场景:
# 函数的文档字符串——这是最正式的用法defcalculate_area(length,width):""" 计算矩形的面积。 参数: length (float): 矩形的长度 width (float): 矩形的宽度 返回: float: 矩形的面积 """returnlength*width# 代码顶部的模块说明''' 模块名:用户管理 功能:处理用户的注册、登录、信息修改等操作 作者:张三 日期:2025-05-30 版本:v1.0 '''# 临时注释掉一大段代码''' print('这段代码暂时不需要执行') print('先用三个引号把它包起来') print('等需要的时候再解开') '''2.3 文档字符串(docstring)
文档字符串是Python中的特殊注释形式,它用"""..."""包裹,写在函数、类、模块的第一行。它和普通注释最大的区别是:文档字符串可以被程序读取。
defgreet(name,greeting='你好'):"""向指定的人打招呼。 Args: name: 被问候的人的名字 greeting: 问候语,默认为"你好" Returns: str: 完整的问候语字符串 Examples: >>> greet('小明') '你好,小明!' >>> greet('小红', '嗨') '嗨,小红!' """returnf'{greeting},{name}!'# 文档字符串可以通过__doc__属性被程序访问print(greet.__doc__)# 输出上面写的整个文档# 也可以用help()函数查看help(greet)# 输出格式化的文档💡 养成写文档字符串的好习惯。对于你自己定义的函数和类,花一分钟写一个简短的文档字符串,几个月后你会感谢现在的自己。
三、什么时候该写注释
3.1 必须写注释的场景
场景一:解释"为什么",而不是"是什么"
❌ 没有意义的注释(只是在重复代码):
x=x+1# 将x加1✅ 有价值的注释(解释了原因):
x=x+1# 补偿索引偏移,因为用户输入的序号从1开始而不是0场景二:非显而易见的算法或逻辑
# 使用埃拉托斯特尼筛法找出所有质数defsieve_of_eratosthenes(n):is_prime=[True]*(n+1)is_prime[0]=is_prime[1]=False# 只需要检查到sqrt(n),因为如果n是合数,# 它必定有一个因子小于等于sqrt(n)foriinrange(2,int(n**0.5)+1):ifis_prime[i]:forjinrange(i*i,n+1,i):is_prime[j]=Falsereturn[iforiinrange(2,n+1)ifis_prime[i]]场景三:带有特殊限制或注意事项的代码
# 注意:这个函数假设输入列表已按升序排列# 如果列表未排序,返回的结果将是错误的defbinary_search(sorted_list,target):# ... 二分查找的实现场景四:解决特定bug的代码
# 在Windows上,文件路径中的反斜杠需要转义# 使用os.path.join可以避免平台差异importos file_path=os.path.join('data','users','info.csv')场景五:TODO和FIXME标记
# TODO: 这里的错误处理需要完善,目前只在理想情况下工作# FIXME: 当用户名为空时会崩溃,需要添加空值检查# HACK: 这是一个临时方案,等后端接口好了之后要重构3.2 不需要写注释的场景
不需要注释一:代码本身已经足够清晰
# 不需要注释name='小明'# 设置名字为小明age=20# 设置年龄为20# 上面的注释完全是废话,代码已经说得很清楚了不需要注释二:可以从良好命名中直接看出的逻辑
# 不需要注释——函数名和变量名已经说明了一切defcalculate_average_score(scores):total=sum(scores)count=len(scores)returntotal/count不需要注释三:可以抽取为函数的复杂逻辑
# ❌ 一大段需要注释的复杂代码defprocess_order(order):# 首先验证订单状态,必须是"待发货"# 然后检查库存是否充足# 如果库存足够,扣减库存# 最后更新订单状态为"已发货"# ... 20行代码pass# ✅ 拆分为小函数,函数名本身就是最好的注释defprocess_order(order):validate_order(order)check_inventory(order)deduct_inventory(order)update_order_status(order,'已发货')四、注释的黄金法则
4.1 注释解释"为什么",代码说明"是什么"
# ❌ 坏注释:重复代码# 遍历员工列表foremployeeinemployees:# 计算工资salary=employee.hours*employee.hourly_rate# 打印工资print(salary)# ✅ 好注释:解释背后的意图foremployeeinemployees:salary=employee.hours*employee.hourly_rate# 根据公司政策,加班时间按1.5倍计算ifemployee.hours>40:overtime_hours=employee.hours-40salary+=overtime_hours*employee.hourly_rate*0.5print(salary)4.2 注释要保持更新
⚠️ 最危险的注释是过时的注释——代码已经改了,但注释没有同步更新。
# ❌ 危险的过时注释defcalculate_tax(income):# 使用2018年的税率(实际上2025年已经改了!)ifincome<5000:return0elifincome<8000:returnincome*0.03# ...# ✅ 更好的做法:用清楚的代码代替注释# 税率表直接来自数据,代码本身说明了逻辑TAX_BRACKETS_2025=[(0,5000,0),(5000,8000,0.03),(8000,17000,0.10),# ...]defcalculate_tax(income):forlower,upper,rateinTAX_BRACKETS_2025:iflower<=income<upper:return(income-lower)*rate4.3 注释用英文还是中文
这是中文开发者经常纠结的问题。我的建议:
- 个人项目 / 学习笔记:用中文,表达更顺畅
- 团队项目 / 开源项目:遵循项目已有的规范。通常建议用英文(方便国际协作)
- docstring:如果项目可能开源,建议中英文都写,或者写英文
# 个人学习项目——中文注释完全OKdefbinary_search(arr,target):"""二分查找算法"""left,right=0,len(arr)-1whileleft<=right:mid=(left+right)//2ifarr[mid]==target:returnmid# 找到了elifarr[mid]<target:left=mid+1# 目标在右半部分else:right=mid-1# 目标在左半部分return-1# 没找到五、实战:给一段代码写注释
让我们通过一个实际例子,看看有注释和没有注释的代码有什么区别。
5.1 没有注释的版本
deff(d,p):r=[]fork,vind.items():ifp(v):r.append(k)returnr data={'a':85,'b':42,'c':96,'d':58,'e':73}print(f(data,lambdax:x>=60))你能一眼看出这个程序在做什么吗?可能需要花点时间。
5.2 加了注释的版本
""" 学生成绩筛选程序 功能:从学生成绩字典中筛选出及格(>=60分)的学生名单 """deffilter_by_criteria(data_dict,check_function):""" 根据指定的筛选条件,从字典中筛选出符合条件的键。 参数: data_dict (dict): 待筛选的字典,键为学生名,值为成绩 check_function (callable): 筛选函数,接受一个值,返回True/False 返回: list: 符合条件的键(学生名)列表 示例: >>> scores = {'小明': 85, '小红': 42} >>> filter_by_criteria(scores, lambda x: x >= 60) ['小明'] """passed_keys=[]# 存储符合条件的学生名forkey,valueindata_dict.items():ifcheck_function(value):passed_keys.append(key)# 该学生成绩符合条件,加入结果returnpassed_keys# 学生成绩数据student_scores={'小明':85,'小红':42,'小刚':96,'小丽':58,'小华':73}# 筛选条件:成绩大于等于60分(及格线)defis_passing(score):returnscore>=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)}人')✅ 现在代码的意思非常清楚了。虽然代码行数变多了,但可读性提升了不止一个档次。好的命名加上适当的注释,让这段代码即使给一个完全没见过的开发者看,也能立刻理解它在做什么。
六、各种语言的注释对比
了解其他语言的注释方式,有助于你理解Python注释的特点:
| 语言 | 单行注释 | 多行注释 |
|---|---|---|
| Python | # 注释 | '''注释'''或"""注释""" |
| C/C++/Java | // 注释 | /* 注释 */ |
| JavaScript | // 注释 | /* 注释 */ |
| SQL | -- 注释 | /* 注释 */ |
| Bash/Shell | # 注释 | : '注释' |
| HTML | N/A | <!-- 注释 --> |
Python不像C/Java那样有专门的多行注释语法,而是巧妙地将字符串字面量复用作多行注释。这个设计体现了Python的极简哲学——少即是多。
七、注释在调试中的妙用
7.1 逐段排查bug
当程序出问题时,注释是最高效的调试工具之一:
defcomplex_calculation(data):# 第一步:数据清洗cleaned_data=clean_data(data)print(f'清洗后数据条数:{len(cleaned_data)}')# 第二步:数据转换(怀疑这里有bug,先注释掉后面,只看前面的输出)# transformed_data = transform_data(cleaned_data)# print(f'转换后数据条数:{len(transformed_data)}')# 第三步:计算# result = calculate(transformed_data)# return result# 暂时返回None,等排查完bug再恢复returnNone7.2 用注释做"版本控制"
在学习和实验阶段,可以保留多种写法做对比:
# 写法一:使用列表推导式# squared = [x**2 for x in range(10)]# 写法二:使用map函数# squared = list(map(lambda x: x**2, range(10)))# 写法三:传统for循环——当前采用这种写法,最易读squared=[]forxinrange(10):squared.append(x**2)print(squared)八、本篇小结
✅ 注释是写给人的,不是写给机器的。机器根本看不懂你的注释,但三个月后的你自己会感激今天的注释。
核心要点回顾:
- 三种注释方式:
#单行、'''/"""多行、docstring文档字符串 - 注释解释"为什么",不要只重复"是什么"
- 保持注释和代码同步,过时的注释比没有注释更危险
- 好的命名是注释的替代品——当代码自己就能说清楚意思时,不需要额外注释
- 关键逻辑必须注释:算法原理、业务规则、特殊限制、已知问题
💡 写注释是一种代码素养。它不是额外的负担,而是编码过程中自然的一部分。从今天开始,每写一段代码,养成问自己"别人读到这里能明白吗"的习惯。下一篇我们将进入Python的基础语法——缩进规则和代码块规范。
