Skip to content

Python 函数

函数是旨在执行特定任务的可重用代码的命名块。函数有助于组织代码、使应用程序更模块化、提高可读性并促进代码重用。

Python 提供了许多内置函数(例如 print()、len()、type())。您也可以定义自己的函数,称为用户自定义函数。

函数使用 def 关键字定义,后跟函数名称、括号 () 和冒号 :。函数内的代码块必须缩进。

  • 语法以 def function_name(parameters): 开头。
  • 参数(函数的输入)列在括号内,用逗号分隔。函数可以有零个或多个参数。
  • 第一个语句 可以 是一个可选的文档字符串(docstring),用三重引号("""这里是文档字符串""")括起来,解释函数的功能。强烈建议这样做。
  • 冒号后的缩进代码块是函数体(suite)。
  • return 语句退出函数并可选地将一个值发送回调用者。如果省略 return 或不带表达式使用,函数将隐式返回 None。
def function_name(parameter1, parameter2=default_value):
"""可选的文档字符串,解释函数功能。"""
# 函数体(缩进代码)
result = parameter1 + parameter2
return result # 可选的 return 语句

一个接受名字并打印问候语的简单函数:

def greet(name):
"""打印一个简单的问候语给定的名字。"""
print(f"Hello, {name}!")
# 隐式返回 None

定义函数并不会执行它。要运行函数内的代码,您必须 调用 它,方法是使用函数名称后跟括号,并提供任何必需的参数。

# 首先定义函数
def greet(name):
"""打印一个简单的问候语。"""
print(f"Hello, {name}!")
# 现在调用函数
greet("Alice")
greet("Bob")

输出:

Hello, Alice!
Hello, Bob!

在 Python 中,参数传递使用一种有时被称为“按对象引用传递”或“按赋值传递”的机制。其含义如下:

示例(可变对象):

def modify_list(my_list):
"""向传递的列表中添加一个项。"""
my_list.append(100) # 修改原始列表对象
print(f"函数内部: {my_list}")
numbers = [10, 20, 30]
modify_list(numbers)
print(f"函数外部: {numbers}") # 修改保留

输出:

Inside function: [10, 20, 30, 100]
Outside function: [10, 20, 30, 100]

示例(重新赋值):

def reassign_list(my_list):
"""将参数重新赋值给一个新列表。"""
my_list = [1, 2, 3, 4] # 参数现在指向一个 *新* 列表
print(f"函数内部 (重新赋值后): {my_list}")
numbers = [10, 20, 30]
reassign_list(numbers)
print(f"函数外部: {numbers}") # 原始列表不受影响

输出:

Inside function (after reassign): [1, 2, 3, 4]
Outside function: [10, 20, 30]

Python 提供了灵活的方式来定义和调用具有不同参数类型的函数:

这些是标准参数,根据其顺序进行匹配。调用时提供的参数数量必须与定义的参数数量一致。

def describe_pet(animal_type, pet_name):
print(f"I have a {animal_type} named {pet_name}.")
describe_pet("hamster", "Harry") # 正确的顺序
# describe_pet("Fluffy") # TypeError: 缺少1个必需的位置参数: 'pet_name'

您可以在函数调用中通过参数名称来指定参数。这允许您不按顺序传递参数,并提高了代码的清晰度。

def describe_pet(animal_type, pet_name):
print(f"I have a {animal_type} named {pet_name}.")
describe_pet(pet_name="Willie", animal_type="dog") # 顺序无关紧要
describe_pet(animal_type="cat", pet_name="Whiskers")

您可以在函数定义中为参数提供默认值。如果在调用中没有为该参数提供参数,则使用默认值。带有默认值的参数必须位于没有默认值的参数 之后。

def describe_pet(pet_name, animal_type="dog"): # animal_type 的默认值
print(f"I have a {animal_type} named {pet_name}.")
describe_pet(pet_name="Buddy") # 使用默认的 animal_type 'dog'
describe_pet(pet_name="Lucy", animal_type="cat") # 覆盖默认值

输出:

I have a dog named Buddy.
I have a cat named Lucy.

要让函数接受任意数量的 位置 参数,可以在参数名称前使用星号 *(通常约定为 *args)。这将把任何额外的按位置传递的参数收集到一个元组 (tuple) 中。

def make_pizza(size, *toppings):
"""打印正在订购的比萨及其配料。"""
print(f"\nMaking a {size}-inch pizza with the following toppings:")
if toppings:
for topping in toppings:
print(f"- {topping}")
else:
print("- Plain")
make_pizza(12, "mushrooms")
make_pizza(16, "pepperoni", "green peppers", "extra cheese")
make_pizza(10) # 没有额外的按位置传递的参数,toppings 是一个空元组

输出:

Making a 12-inch pizza with the following toppings:
- mushrooms
Making a 16-inch pizza with the following toppings:
- pepperoni
- green peppers
- extra cheese
Making a 10-inch pizza with the following toppings:
- Plain

要让函数接受任意数量的 关键字 参数,可以在参数名称前使用两个星号 **(通常约定为 **kwargs)。这将把任何额外的按关键字传递的参数收集到一个字典 (dictionary) 中。

def build_profile(first, last, **user_info):
"""构建一个包含用户信息的字典。"""
profile = {'first_name': first, 'last_name': last}
profile.update(user_info) # 添加任何额外的关键字参数
return profile
user1 = build_profile('albert', 'einstein',
location='princeton',
field='physics')
user2 = build_profile('marie', 'curie', field='chemistry', awards=2)
print(user1)
print(user2)

输出:

{'first_name': 'albert', 'last_name': 'einstein', 'location': 'princeton', 'field': 'physics'}
{'first_name': 'marie', 'last_name': 'curie', 'field': 'chemistry', 'awards': 2}

放在 *args 或裸露的 * 之后 的参数必须使用关键字指定。

def process_data(*, input_file, output_file, force=False):
"""要求 input_file 和 output_file 必须通过关键字传递。"""
print(f"Processing {input_file} to {output_file}. Force={force}")
# process_data("in.txt", "out.txt") # TypeError!
process_data(input_file="in.csv", output_file="out.csv")
process_data(input_file="data.zip", output_file="proc.zip", force=True)

放在裸露的 / 之前 的参数只能通过位置指定,不能使用关键字。

def example_pos_only(a, b, / , c, d):
"""a 和 b 是仅限位置参数。"""
print(f"a={a}, b={b}, c={c}, d={d}")
example_pos_only(1, 2, c=3, d=4) # 工作正常
# example_pos_only(a=1, b=2, c=3, d=4) # TypeError!a 和 b 是仅限位置参数

Lambda 函数提供了一种创建小型匿名函数(没有名称的函数)的简写语法。它们使用 lambda 关键字定义。

  • 语法:lambda arguments: expression
  • 可以接受任意数量的参数,但只能有一个表达式。
  • 当 lambda 被调用时,表达式会被评估并返回。
  • 通常用于需要简单函数对象的地方(例如,作为 map()、filter()、sorted() 的参数)。

示例:

# 等同于: def add(x, y): return x + y
adder = lambda x, y: x + y
print(f"总值: {adder(10, 20)}")
print(f"总值: {adder(5, -2)}")
# 将 lambda 与 sorted() 一起使用
points = [(1, 2), (3, 1), (5, -4), (2, 3)]
# 根据第二个元素 (y 坐标) 对点进行排序
points_sorted_by_y = sorted(points, key=lambda point: point[1])
print(f"按 y 排序: {points_sorted_by_y}")

输出:

Value of total: 30
Value of total: 3
Sorted by y: [(5, -4), (3, 1), (1, 2), (2, 3)]

return 语句用于退出函数并将一个值返回到函数被调用的位置。函数可以返回任何类型的对象。

def subtract(arg1, arg2):
"""从 arg1 中减去 arg2 并返回结果。"""
total = arg1 - arg2
print(f"函数内部,结果: {total}")
return total
# 调用函数并存储返回值
result_value = subtract(20, 5)
print(f"函数外部,结果: {result_value}")
# 可以返回多个值(作为元组)
def get_coordinates():
return 10, 20 # 自动打包成一个元组
x, y = get_coordinates() # 解包返回的元组
print(f"坐标: x={x}, y={y}")

输出:

Inside the function, result: 15
Outside the function, result: 15
Coordinates: x=10, y=20

变量的作用域决定了程序中可以在哪里访问它。

Python 按照 LEGB 顺序搜索变量名。

total = 0 # 全局变量
def sum_and_update(arg1, arg2):
# 除非声明为 global,否则这里的 'total' 指的是一个 *新的* 局部变量
# global total # 取消此行注释以修改全局 'total'
total = arg1 + arg2 # 创建一个局部 'total',遮蔽了全局变量
print(f"函数内部局部 total: {total}")
return total
sum_and_update(10, 20)
print(f"函数外部全局 total: {total}") # 全局 'total' 保持不变

输出(未取消注释 global total):

Inside function local total: 30
Outside function global total: 0

现代 Python (3.5+) 支持可选的类型提示,允许您使用预期的类型来标注函数的参数和返回值。类型提示不影响运行时行为,但对于静态分析工具(如 MyPy)、IDE 和提高代码清晰度非常有价值。

import math
def calculate_circumference(radius: float) -> float:
"""根据半径计算圆的周长。"""
if radius < 0:
raise ValueError("半径不能为负数")
return 2 * math.pi * radius
# 类型提示有助于在静态分析时捕获潜在错误
circum = calculate_circumference(10.5)
print(f"周长: {circum:.2f}")
# 如果运行 Mypy,此调用会被标记:
# result_wrong_type = calculate_circumference("hello")

常见的类型从 typing 模块导入(例如 List、Dict、Tuple、Optional)。