5 个技巧就能写出专业的 Python 代码!

写 Python 函数时,你是不是总被各种问题困扰?函数没写完却没提示,调用时出问题找不到原因;团队协作时,不知道函数返回啥类型,老是出类型错误;想理解个复杂函数,得一行行看代码,费时又费力…… 别愁,5 个技巧帮你搞定,写出专业的 Python 代码!

一、用 NotImplementedError 代替 pass

平时写函数,没写完的时候是不是习惯用 pass 占个位?但这样可不好,要是不小心调用了这个没写完的函数,它不声不响的,出了问题都不知道在哪。这时候就得用 NotImplementedError 了。

比如用 pass 的情况:

def calculate_average(numbers):# 还没写完pass# 不小心调用了calculate_average([1,2,3])  # 啥反应没有,出问题不好找

换成 NotImplementedError 就不一样了:

def calculate_average(numbers):# 还没写完,抛出错误并提示raise NotImplementedError("这个函数还没实现,正在开发中")# 调用的话calculate_average([1,2,3])  # 直接报错,告诉你哪有问题

常见问题和错误

  • 常见问题:有些人觉得 pass 简单就一直用,没意识到潜在风险,尤其是在大型项目中,很容易因为调用了未完成的函数而导致难以排查的错误。

  • 错误情况:把 NotImplementedError 拼错了,比如写成 NotImplementError,这时候会抛出 NameError,要注意正确拼写。

面试相关

面试官可能会问:“在未完成的函数中,用 pass 和 NotImplementedError 有什么区别?”

回答:pass 会让函数静默执行,不产生任何提示,当不小心调用时,出了问题很难排查;而 NotImplementedError 会直接抛出错误,并可以添加提示信息,能快速定位到未完成的函数,适合标记未完成的函数,在大型项目调试中更高效。

二、显式声明返回类型

在函数签名中添加类型注解,好处可不少。IDE 能实时检查类型错误,团队协作时,别人一看就知道函数返回值的结构,能减少数据类型不匹配的 bug。

比如这样给函数加返回类型注解:

def get_users() -> dict[int, str]:return {1: "张三", 2: "李四"}def add_numbers(a: int, b: int) -> int:return a + b

当你在 IDE 中调用这些函数时,如果对返回值进行不符合类型的操作,IDE 就会提示错误。比如:

users = get_users()print(users + 1)  # IDE会提示错误,因为dict不能和int相加

常见问题和错误

  • 常见问题:觉得类型注解麻烦,不愿意添加。但在大型项目和团队协作中,类型注解能大大提高代码的可读性和可维护性。

  • 错误情况:注解的类型和实际返回类型不符。比如函数声明返回 int,实际却返回了 str,虽然 Python 不会强制报错,但会给后续调用带来隐患。

函数声明 实际返回值 可能导致的问题
def func() -> int return "123" 调用时用返回值进行数值运算会出错
def func() -> list return {"a": 1} 调用时用列表的方法操作返回值会出错

面试相关

面试官可能会问:“Python 函数中添加返回类型注解有什么作用?”

回答:添加返回类型注解可以让 IDE 实时检查类型错误,帮助开发者在编写代码时及时发现问题;让其他开发者在调用函数时,一目了然地知道返回值的结构和类型,减少数据类型不匹配的 bug,提高团队协作的效率。

三、添加文档字符串(Docstring)

用三引号注释说明函数功能、参数、返回值,配合 Sphinx 等工具还能生成文档。即使是复杂函数,通过悬停查看注释就能快速理解用途,比读代码逻辑更直接,是代码自文档化的必备技巧。

比如一个有详细文档字符串的函数:

def calculate_area(length: float, width: float) -> float:"""计算长方形的面积参数:length: 长方形的长度,必须是正数width: 长方形的宽度,必须是正数返回值:float: 长方形的面积,即长度乘以宽度示例:>>> calculate_area(3, 4)12.0"""if length <= 0 or width <= 0:raise ValueError("长度和宽度必须是正数")return length * width

在 IDE 中,当你悬停在调用这个函数的地方,就能看到这些注释信息,快速了解函数的用法。

常见问题和错误

  • 常见问题:文档字符串写得太简略,只说明函数功能,不说明参数和返回值,导致别人还是要读代码才能理解。

  • 错误情况:文档字符串的格式不对,比如参数列表的格式混乱,导致生成文档时出现问题。

面试相关

面试官可能会问:“如何让 Python 函数更易被他人理解?”

回答:可以给函数添加详细的文档字符串,用三引号注释说明函数的功能、参数的含义和要求、返回值的类型和意义,还可以加上示例。这样别人不用阅读函数内部的代码逻辑,通过查看文档字符串就能快速理解函数的用法。

四、强制关键字参数

在函数签名中使用 * 分隔位置参数和关键字参数,调用时必须显式传入参数名,能避免因参数顺序错误导致的逻辑问题,让复杂函数调用更清晰。

比如这样定义函数:

def upload(file: str, *, quality: str, privacy: bool):print(f"上传文件: {file},质量: {quality},是否私密: {privacy}")

调用这个函数时,必须显式传入 quality 和 privacy 的参数名:

upload("test.txt", quality="high", privacy=True)  # 正确# upload("test.txt", "high", True)  # 错误,会抛出TypeError

常见问题和错误

  • 常见问题:不知道怎么用 * 分隔位置参数和关键字参数,还是按照原来的方式定义函数,导致调用时可能因为参数顺序错误而出问题。

  • 错误情况:调用函数时,对于强制关键字参数没有显式传入参数名,导致抛出 TypeError。

面试相关

面试官可能会问:“在定义函数时,如何避免调用者因参数顺序错误而导致问题?”

回答:可以在函数签名中使用 * 来分隔位置参数和关键字参数,将一些容易混淆顺序的参数设为强制关键字参数。这样调用者在调用函数时必须显式传入这些参数的名称,从而避免因参数顺序错误导致的逻辑问题。

五、用 * args 处理可变参数

通过 def join_text (*strings, separator) 接收任意数量位置参数,轻松处理动态输入(如拼接多个字符串),让函数灵活性飙升,告别参数数量限制烦恼。

比如这个拼接字符串的函数:

def join_text(*strings, separator: str = " "):"""拼接多个字符串参数:*strings: 要拼接的多个字符串separator: 分隔符,默认为空格返回值:str: 拼接后的字符串"""return separator.join(strings)# 调用示例print(join_text("Hello", "world", "!", separator="-"))  # 输出:Hello-world-!print(join_text("Python", "is", "great"))  # 输出:Python is great

常见问题和错误

  • 常见问题:滥用args,不管什么情况都用args 接收参数,导致函数内部处理参数变得复杂。其实对于参数数量固定的情况,不建议用 * args。

  • 错误情况:args 和其他参数混用不当,比如把args 放在其他参数后面(除了 **kwargs),会导致语法错误。正确的顺序是位置参数、*args、关键字参数、**kwargs。

面试相关

面试官可能会问:“*args 的作用是什么,在什么情况下使用?”

回答:args 用于在函数定义中接收任意数量的位置参数,这些参数会被打包成一个元组在函数内部使用。当函数需要处理动态数量的输入,比如拼接多个字符串、计算多个数的和等情况时,可以使用args,它能增加函数的灵活性,摆脱参数数量的限制。

从错误处理到参数设计,这 5 个技巧针对日常编码中的痛点,能帮助你写出更专业的函数。无论是新手理清逻辑,还是老手优化代码,都能提升开发效率。赶紧把这些技巧用起来,让你的 Python 代码更上一层楼吧!