在 Python 中,函数是组织好的、可重复使用的代码块。调用函数时,我们可以向函数传递数据,这些数据称为参数。参数让函数更加灵活,能够处理不同的输入。
Python 支持多种传递参数的方式,其中最基础也最重要的是位置参数和关键字参数。理解它们的区别和用法,是编写清晰、易用函数的关键。
位置参数 是指调用函数时,实参按照形参定义的顺序依次传递。也就是说,第一个实参传递给第一个形参,第二个实参传递给第二个形参,以此类推。
defdescribe_pet(name, animal_type):
print(f"我有一只{animal_type},名字叫{name}")
describe_pet("旺财", "狗") # 正确:name="旺财", animal_type="狗"
describe_pet("猫", "咪咪") # 错误逻辑:name="猫", animal_type="咪咪"位置参数要求调用者必须记住每个参数的顺序。一旦顺序弄错,虽然语法正确,但函数的行为可能不符合预期(如上面的“猫”变成了名字)。
如果函数定义时需要 n 个位置参数,调用时也必须提供 n 个,否则会引发 TypeError。
defadd(a, b):
return a + b
add(3) # TypeError: add() missing 1 required positional argument: 'b'
add(3, 5, 7) # TypeError: add() takes 2 positional arguments but 3 were given位置参数适合参数较少、顺序自然且不易混淆的情况,例如数学计算函数、简单的设置函数等。
defmultiply(x, y):
return x * y
result = multiply(4, 5) # 清晰明了关键字参数 是指在调用函数时,使用 形参名=值 的形式传递参数。这样,实参与形参通过参数名匹配,而不依赖于位置。
defdescribe_pet(name, animal_type):
print(f"我有一只{animal_type},名字叫{name}")
describe_pet(animal_type="狗", name="旺财") # 顺序无关关键字参数清晰地表明了每个值的含义,使代码更具可读性,尤其当参数较多时。
Python 允许在调用时混合使用位置参数和关键字参数,但位置参数必须出现在关键字参数之前。
deffunc(a, b, c):
print(a, b, c)
func(1, c=3, b=2) # 正确:1 是位置参数,c 和 b 是关键字参数
# func(a=1, 2, 3) # 错误:位置参数不能在关键字参数之后当函数参数较多时,使用关键字参数可以避免混淆,并允许你只指定需要的参数(如果有默认值)。
defcreate_user(name, age, city, job):
print(f"创建用户:{name},年龄:{age},城市:{city},职业:{job}")
# 使用位置参数(需要记住顺序)
create_user("张三", 25, "北京", "工程师")
# 使用关键字参数(一目了然)
create_user(name="李四", job="设计师", city="上海", age=28)defexample(a, b, c):
pass
# 合法调用
example(1, 2, c=3)
example(1, b=2, c=3)
example(a=1, b=2, c=3)
# 非法调用
example(1, b=2, 3) # SyntaxError: positional argument follows keyword argument
example(1, 2, a=3) # TypeError: example() got multiple values for argument 'a'
example(1, 2, d=4) # TypeError: example() got an unexpected keyword argument 'd'在某些情况下,我们希望强制调用者使用关键字参数传递某些参数,以提高代码可读性或避免歧义。Python 提供了 * 语法来实现这一点。
在函数定义中,单独使用一个 * 表示后面的参数必须作为关键字参数传递。
defregister(name, age, *, city, job):
print(f"{name},{age}岁,来自{city},职业{job}")
# 合法调用
register("张三", 25, city="北京", job="工程师")
# 非法调用
register("张三", 25, "北京", "工程师") # TypeError: register() takes 2 positional arguments but 4 were given这里的 city 和 job 就是命名关键字参数,它们没有默认值,因此调用时必须提供,且必须使用关键字形式。
如果命名关键字参数也有默认值,则可以省略:
defregister(name, age, *, city="未知", job="无"):
print(f"{name},{age}岁,来自{city},职业{job}")
register("李四", 30) # 李四,30岁,来自未知,职业无
register("王五", 28, city="上海", job="教师") # 王五,28岁,来自上海,职业教师defadd_student(name, grade, class_num, score):
print(f"添加学生:{name},年级{grade},班级{class_num},分数{score}")
# 位置参数方式(需记住顺序)
add_student("小明", 3, 2, 95)
# 关键字参数方式(清晰)
add_student(name="小红", score=88, grade=4, class_num=1)defdraw_point(x, y, color, size):
print(f"在({x},{y})绘制{color}色点,大小{size}")
# 混合使用(x,y必须按位置,color和size用关键字)
draw_point(10, 20, color="red", size=5)
draw_point(30, 40, size=3, color="blue")defsend_email(to, subject, *, cc=None, bcc=None):
print(f"发送邮件给{to},主题:{subject}")
if cc:
print(f"抄送:{cc}")
if bcc:
print(f"密送:{bcc}")
# 正确调用
send_email("user@example.com", "会议通知", cc="manager@example.com")
send_email("user@example.com", "问候", bcc="archive@example.com")
# 错误:cc 必须用关键字
# send_email("user@example.com", "通知", "someone@example.com")TypeError。TypeError。SyntaxError。TypeError。* 之后,且在定义时不能使用位置形式调用。
* 可以强制某些参数必须以关键字形式传递,提高代码清晰度。掌握位置参数与关键字参数,是编写灵活、健壮函数的基础。在实际开发中,根据函数的特点和调用场景合理选择参数传递方式,能让你的代码更易读、更易维护。