【Python-Day 17】玩转函数参数(上):轻松掌握位置、关键字和默认值

Langchain系列文章目录

01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
08-【万字长文】MCP深度解析:打通AI与世界的“USB-C”,模型上下文协议原理、实践与未来

Python系列文章目录

PyTorch系列文章目录

机器学习系列文章目录

深度学习系列文章目录

Java系列文章目录

JavaScript系列文章目录

Python系列文章目录

01-【Python-Day 1】告别编程恐惧:轻松掌握 Python 安装与第一个程序的 6 个步骤
02-【Python-Day 2】掌握Python基石:变量、内存、标识符及int/float/bool数据类型
03-【Python-Day 3】玩转文本:字符串(String)基础操作详解 (上)
04-【Python-Day 4】玩转文本:Python 字符串常用方法深度解析 (下篇)
05-【Python-Day 5】Python 格式化输出实战:%、format()、f-string 对比与最佳实践
06- 【Python-Day 6】从零精通 Python 运算符(上):算术、赋值与比较运算全解析
07-【Python-Day 7】从零精通 Python 运算符(下):逻辑、成员、身份运算与优先级规则全解析
08-【Python-Day 8】从入门到精通:Python 条件判断 if-elif-else 语句全解析
09-【Python-Day 9】掌握循环利器:for 循环遍历序列与可迭代对象详解
10-【Python-Day 10】Python 循环控制流:while 循环详解与 for 循环对比
11-【Python-Day 11】列表入门:Python 中最灵活的数据容器 (创建、索引、切片)
12-【Python-Day 12】Python列表进阶:玩转添加、删除、排序与列表推导式
13-【Python-Day 13】Python 元组 (Tuple) 详解:从创建、操作到高级应用场景一网打尽
14-【Python-Day 14】玩转Python字典(上篇):从零开始学习创建、访问与操作
15-【Python-Day 15】深入探索 Python 字典 (下):常用方法、遍历、推导式与嵌套实战
16-【Python-Day 16】代码复用基石:详解 Python 函数的定义与调用
17-【Python-Day 17】玩转函数参数(上):轻松掌握位置、关键字和默认值



前言

大家好!欢迎来到 Python 学习系列的第 17 天。在上一篇文章中,我们学习了如何定义和调用函数,迈出了代码复用的重要一步。然而,要让函数真正强大和灵活起来,我们必须掌握如何向函数传递信息——这就是参数的作用。Python 提供了多种传递参数的方式,使得函数调用变得异常灵活。今天,我们将深入探讨函数参数中的位置参数关键字参数以及默认参数,理解它们的工作原理和使用场景,为编写更强大、更通用的函数打下坚实的基础。让我们一起开始吧!

一、为什么需要不同类型的参数?

想象一下,函数就像一个加工机器,而参数就是我们送入机器的原材料。不同的任务可能需要不同种类、不同数量的原材料,甚至有些原材料有“标准配置”,而另一些则需要我们特别指定。Python 的设计者们正是考虑到了这种多样性,才设计了多种参数类型:

  • 灵活性:允许我们根据需要,选择最方便、最清晰的方式传递数据。
  • 可读性:特别是关键字参数,能让函数调用变得像自然语言一样易于理解。
  • 健壮性:默认参数可以减少不必要的参数传递,简化函数调用,并提供备选方案。
  • 扩展性:未来的可变参数(我们将在下一篇讨论)将进一步增强函数的适应能力。

理解这些参数类型,就像学习如何精确地控制你的“加工机器”,让它能高效、准确地完成各种任务。

二、位置参数 (Positional Arguments)

位置参数是我们最先接触,也是最基本的一种参数传递方式。顾名思义,它的核心在于 “位置” —— 实参(调用函数时传递的值)和形参(定义函数时声明的变量)是按照它们各自出现的顺序一一对应的。

2.1 什么是位置参数?

在定义函数时,我们按顺序写下的参数就是位置参数。在调用函数时,我们同样按顺序提供的值,会依次赋给这些参数。

def describe_pet(animal_type, pet_name):
  """显示宠物的信息"""
  print(f"\n我有一只 {animal_type}。")
  print(f"它的名字叫 {pet_name.title()}。")

# 调用函数 - 'dog' 对应 animal_type, '旺财' 对应 pet_name
describe_pet('dog', '旺财')
describe_pet('cat', '咪咪')

2.2 位置参数的特点

2.2.1 顺序至关重要

这是位置参数最显著的特点。如果传递实参的顺序与定义形参的顺序不一致,可能会导致逻辑错误,甚至程序崩溃。

# 错误的顺序调用
describe_pet('小黑', 'hamster')

输出:

我有一只 小黑。
它的名字叫 Hamster。

看,程序没有报错,但输出的意义完全错了!“小黑” 成了类型,“hamster” 成了名字。

2.2.2 数量必须匹配

调用函数时传递的位置参数数量,必须与函数定义中要求的位置参数数量完全一致。

(1) 数量过少
describe_pet('bird') # 只提供了一个参数

输出:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: describe_pet() missing 1 required positional argument: 'pet_name'

Python 会明确告诉你缺少了哪个参数。

(2) 数量过多
describe_pet('fish', '尼莫', '蓝色') # 提供了三个参数

输出:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: describe_pet() takes 2 positional arguments but 3 were given

Python 也会告诉你提供了过多的参数。

2.3 位置参数的适用场景

位置参数最适合用于那些参数含义清晰、顺序固定且数量较少的函数。例如,一个计算两数之和的函数 add(a, b)ab 的顺序通常不重要(除非有特殊要求),而且含义明确,使用位置参数就非常自然。

三、关键字参数 (Keyword Arguments)

为了解决位置参数严格依赖顺序的问题,并提高代码的可读性,Python 引入了关键字参数。它允许我们在调用函数时,明确指定哪个值传递给哪个参数。

3.1 什么是关键字参数?

关键字参数是在函数调用时,使用 key=value 的形式来传递参数。这里的 key 就是函数定义时的形参名。

def describe_pet(animal_type, pet_name):
  """显示宠物的信息"""
  print(f"\n我有一只 {animal_type}。")
  print(f"它的名字叫 {pet_name.title()}。")

# 使用关键字参数调用
describe_pet(animal_type='dog', pet_name='大黄')
describe_pet(pet_name='雪球', animal_type='rabbit') # 顺序变了,但结果正确

输出:

我有一只 dog。
它的名字叫 大黄。

我有一只 rabbit。
它的名字叫 雪球。

可以看到,即使我们改变了 pet_nameanimal_type 的顺序,由于我们明确指定了它们的值,函数依然能正确工作。

3.2 关键字参数的特点

3.2.1 顺序不再重要

这是关键字参数最大的优势之一。只要你正确指定了参数名,它们的顺序可以随意调整,这大大降低了因顺序错误导致的 bug。

3.2.2 提高代码可读性

当函数参数较多时,func(10, 'John', True, 55.0) 这样的调用可能让人难以理解每个值的含义。而 func(age=10, name='John', is_student=True, weight=55.0) 则一目了然。

3.2.3 必须与形参名匹配

你使用的关键字必须是函数定义中存在的形参名,否则会引发 TypeError

describe_pet(animal='cat', name='咪咪')

输出:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: describe_pet() got an unexpected keyword argument 'animal'

3.3 混合使用位置参数和关键字参数

Python 允许我们混合使用这两种参数,但有一个重要规则所有位置参数必须出现在所有关键字参数之前

# 正确的混合使用
describe_pet('cat', pet_name='花花')

# 错误的使用:关键字参数在位置参数之前
# describe_pet(animal_type='dog', '小白') # 这会导致 SyntaxError

3.4 关键字参数的适用场景

当函数参数较多,或者参数的含义不通过名称难以区分时,强烈推荐使用关键字参数。它也是可选参数(如下面的默认参数)的常用传递方式。

四、默认参数 (Default Arguments)

有时候,函数的某些参数在大多数情况下都会取一个固定的值。为了简化函数调用,我们可以为这些参数设置一个默认值

4.1 什么是默认参数?

在定义函数时,我们可以给某些形参赋一个初始值。如果在调用函数时没有为这些参数提供值,那么它们就会自动使用这个默认值。

def describe_pet(pet_name, animal_type='dog'): # animal_type 设置了默认值
  """显示宠物的信息,默认宠物类型是狗"""
  print(f"\n我有一只 {animal_type}。")
  print(f"它的名字叫 {pet_name.title()}。")

# 只提供必需的参数,使用默认值
describe_pet('旺财')

# 提供所有参数,覆盖默认值
describe_pet('咪咪', 'cat')

# 使用关键字参数,覆盖默认值
describe_pet(pet_name='皮皮', animal_type='parrot')

# 使用关键字参数,只提供必需的
describe_pet(pet_name='小金')

输出:

我有一只 dog。
它的名字叫 旺财。

我有一只 cat。
它的名字叫 咪咪。

我有一只 parrot。
它的名字叫 皮皮。

我有一只 dog。
它的名字叫 小金。

4.2 定义默认参数的规则

4.2.1 默认参数必须在非默认参数之后

在函数定义时,所有带默认值的参数必须放在所有不带默认值的参数(即普通位置参数)的后面

# 错误的定义
# def describe_pet(animal_type='dog', pet_name): # SyntaxError
#   ...

# 正确的定义
def describe_pet(pet_name, animal_type='dog'):
  ...

这是因为 Python 解释器需要明确知道你传递的位置参数是对应哪个形参。如果默认参数在前面,会产生歧义。

4.3 默认参数的重要“坑”:可变对象

这是一个非常关键且常见的错误点!不要使用可变对象(如列表 [] 或字典 {})作为默认参数值

为什么?因为默认参数的值是在函数定义时被创建和计算的,而不是在每次调用时。如果默认值是一个可变对象,那么所有使用该默认值的调用都会共享同一个对象。

4.3.1 错误的示例

def add_to_list(item, my_list=[]):
  """将项目添加到列表中(错误的默认参数用法)"""
  my_list.append(item)
  print(f"Adding {item}, list is now: {my_list}")
  return my_list

list1 = add_to_list('apple')
list2 = add_to_list('banana') # 期望是 ['banana'],但结果会出乎意料
list3 = add_to_list('cherry')

输出:

Adding apple, list is now: ['apple']
Adding banana, list is now: ['apple', 'banana']
Adding cherry, list is now: ['apple', 'banana', 'cherry']

看到了吗?list2list3 并没有从一个空列表开始,而是继续在 list1 的基础上添加!这是因为它们共享了函数定义时创建的那个 []

4.3.2 正确的解决方案

正确的做法是将默认值设为 None,然后在函数内部检查,如果参数是 None,再创建一个新的可变对象。

def add_to_list_correct(item, my_list=None):
  """将项目添加到列表中(正确的默认参数用法)"""
  if my_list is None:
    my_list = [] # 在函数调用时创建新列表
  my_list.append(item)
  print(f"Adding {item}, list is now: {my_list}")
  return my_list

list_a = add_to_list_correct('apple')
list_b = add_to_list_correct('banana') # 这次结果正确了!
list_c = add_to_list_correct('cherry')

输出:

Adding apple, list is now: ['apple']
Adding banana, list is now: ['banana']
Adding cherry, list is now: ['cherry']

请务必牢记这一点,这是 Python 中一个非常重要的细节!

4.4 默认参数的适用场景

默认参数非常适合用于那些有“常用设置”或“可选配置”的函数。它能让函数调用更简洁,同时保留了自定义的灵活性。例如,文件操作函数中的编码方式、网络请求中的超时时间等,都可以设置默认值。

五、参数组合使用的规则与场景

当我们把这三种参数结合起来时,需要遵循一定的顺序和规则:

  1. 定义顺序位置参数 -> 默认参数
  2. 调用顺序位置参数 -> 关键字参数。(关键字参数可以用来指定任何参数,包括有默认值的)。
def create_profile(name, age, city='北京', *, language='Python'):
    """
    创建一个用户资料。
    name 和 age 是位置参数。
    city 是默认参数。
    language 是强制关键字参数 (我们将在下一篇详细介绍 * 的用法,
    这里你可以暂时理解为 language 必须用关键字参数传递)。
    """
    print(f"姓名: {name}")
    print(f"年龄: {age}")
    print(f"城市: {city}")
    print(f"语言: {language}")

# 各种调用方式
print("--- 1 ---")
create_profile('张三', 25) # 使用 city 的默认值

print("\n--- 2 ---")
create_profile('李四', 30, city='上海') # 使用关键字参数覆盖 city

print("\n--- 3 ---")
create_profile('王五', 22, language='Java') # 使用 city 默认值,指定 language

print("\n--- 4 ---")
create_profile('赵六', 35, '广州', language='Go') # 位置参数指定 city,关键字指定 language

print("\n--- 5 ---")
create_profile(name='钱七', age=28, city='深圳', language='Ruby') # 全部使用关键字参数

思考

  • 为什么 create_profile('张三', 25, 'Python') 会失败?(因为 language 被设计为必须用关键字传递)。
  • 为什么 create_profile(age=30, name='李四') 能成功?(关键字参数无视顺序)。

选择哪种参数取决于你的具体需求:

  • 必需且顺序固定 -> 位置参数。
  • 参数多或想提高可读性 -> 关键字参数。
  • 可选或有常用值 -> 默认参数。

六、总结

今天,我们详细探讨了 Python 函数参数的三种基本类型,它们是构建灵活、强大函数的基础:

  1. 位置参数 (Positional Arguments)
    • 通过参数的顺序进行匹配。
    • 顺序数量都必须严格对应。
    • 简单直观,适用于参数少且固定的情况。
  2. 关键字参数 (Keyword Arguments)
    • 通过 key=value 的形式传递,与顺序无关
    • 提高了代码的可读性灵活性
    • 混合使用时,必须放在位置参数之后
  3. 默认参数 (Default Arguments)
    • 在函数定义时为参数提供默认值,简化调用。
    • 必须放在非默认参数之后
    • 极其重要避免使用可变对象(如 []{})作为默认值,应使用 None 配合函数内部检查来替代。

掌握了这些参数类型,你就能够更自如地设计和使用函数了。在下一篇文章中,我们将继续探索更高级的参数类型:可变参数 (*args**kwargs),它们将赋予你的函数处理任意数量参数的能力!敬请期待!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吴师兄大模型

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值