是什么
函数 = 一段被命名的、可重复使用的代码块
函数(function)是带名字的代码块,用于完成具体的工作。要执行函数定义的特定任务,可调用(call)该函数。当需要在程序中多次执行同一项任务时,无须反复编写完成该任务的代码,只需要调用执行该任务的函数。它接收输入(参数),执行特定操作,返回结果(或无结果)。
定义一个函数
- 函数代码块以
def关键词开头,后接函数标识符名称和圆括号 ()。 - 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以
冒号(:)起始,并且缩进。 return [表达式]结束函数,选择性地返回一个值给调用方,不带return 表达式的函数相当于返回None。

def functionname( parameters ):
"函数_文档字符串"
function_suite
return [expression]
定义一个空函数
如果想定义一个什么事也不做的空函数,可以用pass语句,缺少了pass,代码运行就会有语法错误,空函数无法被调用。
pass语句什么都不做,那有什么用?
实际上pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。
def empty_fun():
pass
返回多个值
Python 的函数可以返回多个值。
比如在游戏中经常需要从一个点移动到另一个点,给出坐标、位移和角度,就可以计算出新的坐标:
import math
def move(x, y, step, angle=0):
nx = x + step * math.cos(angle)
ny = y - step * math.sin(angle)
return nx, ny
import math语句表示导入math包,并允许后续代码引用math包里的sin、cos等函数。
然后,我们就可以同时获得返回值:
>>> x, y = move(100, 100, 60, math.pi / 6)
>>> print(x, y)
151.96152422706632 70.0
但其实这只是一种假象,Python函数返回的仍然是单一值:
>>> r = move(100, 100, 60, math.pi / 6)
>>> print(r)
(151.96152422706632, 70.0)
原来返回值是一个tuple!但是,在语法上,返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple,按位置赋给对应的值,所以,Python的函数返回多值其实就是返回一个tuple,但写起来更方便。
Python类型注解(Type Hints)
类型注解是 Python 从动态语言向‘可维护性语言’进化的重要一步。在 Python 中,类型注解不是必须的,但它是让代码清晰的‘最佳实践’。
类型注解 = 在函数、变量上添加类型信息,但 不 改变运行时行为
它只用于静态类型检查(如 PyCharm、mypy),不用于运行时类型检查。
基本语法
def add(a: int, b: int) -> int:
"""添加两个整数"""
return a + b
# 调用
print(add(3, 4)) # 7
变量类型注解
name: str = "Alice"
age: int = 30
is_active: bool = True
高级类型注解
集合类型(List, Dict, Tuple)
from typing import List, Dict, Tuple
# 列表:整数列表
numbers: List[int] = [1, 2, 3]
# 字典:字符串->整数映射
user: Dict[str, int] = {"id": 123, "age": 30}
# 元组:固定长度的元组
point: Tuple[float, float] = (3.5, 4.2)
可选类型(Optional)
from typing import Optional
def get_user(id: int) -> Optional[Dict[str, int]]:
"""可能返回用户,也可能返回 None"""
if id == 0:
return None
return {"id": id, "name": "Alice"}
user = get_user(123)
if user is not None:
print(user["name"])
参数传递
在 python 中,类型属于对象,对象有不同类型的区分,变量是没有类型的:
a = [1, 2, 3]
a = "Runoob"
以上代码中,[1,2,3] 是 List 类型,“Runoob” 是 String 类型,而变量 a 是没有类型,它仅仅是一个对象的引用(一个指针),可以是指向 List 类型对象,也可以是指向 String 类型对象。
Python中一切都是对象,所以严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。
可更改(mutable)对象
类似 C++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后 fun 外部的 la 也会受影响。
'''
在Python函数的参数传递,主要分参数类型:
- 不可变类型
- 可变类型
**不可变对象类型**:
也即值传递,如整数、浮点数、字符串、元组等。
比如如def fun(a):,传递的只是a的值,没有传递a对象的地址。比如在fun(a)内部修改a的值,
只是修改另一个复制的对象的值,不会影响 a 本身对象的值。
**可变对象类型**:
也即引用(地址)传递,如列表,集合、字典等。如def fun(la):,则是将 la对象地址传过去,修改后fun外部的la也会受影响。
'''
# 传入可变(mutable)对象类型参数案例
def change_list(my_list) :
my_list[1] = 50
print("函数内的值",my_list)
print("函数内列表的内存",id(my_list))
m_list = [1,2,3]
change_list(m_list)
print("函数外的值",m_list)
print("函数外列表的内存",id(m_list))
# 输出结果
#函数内的值 [1, 50, 3]
#函数内列表的内存 1149137300800
#函数外的值 [1, 50, 3]
#函数外列表的内存 1149137300800
不可更改(immutable)对象
类似 C++ 的值传递,如整数、字符串、元组。如 fun(a),传递的只是 a 的值,没有影响 a 对象本身。如果在 fun(a) 内部修改 a 的值,则是新生成一个 a 的对象。
'''
在Python函数的参数传递,主要分参数类型:
- 不可变类型
- 可变类型
**不可变对象类型**:
也即值传递,如整数、浮点数、字符串、元组等。
比如如def fun(a):,传递的只是a的值,没有传递a对象的地址。比如在fun(a)内部修改a的值,
只是修改另一个复制的对象的值,不会影响 a 本身对象的值。
**可变对象类型**:
也即引用(地址)传递,如列表,集合、字典等。如def fun(la):,则是将 la对象地址传过去,修改后fun外部的la也会受影响。
'''
# 传入不可变(immutable)对象类型参数案例
def change_int(a:int) ->None:
print("函数体中未改变前a的内存地址",id(a))
a = 10
print("函数体中改变后a的内存地址",id(a))
a = 2
change_int(a)
print(a)
print("函数外b的内存地址",id(a))
# 输出结果
#函数体中未改变前a的内存地址 140733455352776
#函数体中改变后a的内存地址 140733455353032
#2
#函数外b的内存地址 140733455352776
参数
调用函数时可使用的正式参数类型:
- 必需参数
- 关键字参数
- 默认参数
- 不定长参数
不定长参数
*args:接收任意数量的位置参数
当函数需要处理不确定数量的参数时(如 <font style="color:rgb(6, 10, 38);">sum(1, 2, 3, 4)</font>),Python 用 <font style="color:rgb(6, 10, 38);">*args</font> 解决。
def sum_all(*args):
"""接收任意数量的位置参数"""
total = 0
for num in args:
total += num
return total
print(sum_all(1, 2, 3)) # 6
print(sum_all(10, 20, 30, 40)) # 100
**kwargs:接收任意数量的关键字参数
当函数需要处理不确定数量的命名参数时(如 <font style="color:rgb(6, 10, 38);">config(key1="value1", key2="value2")</font>),Python 用 <font style="color:rgb(6, 10, 38);">**kwargs</font> 解决。
def print_config(**kwargs):
"""接收任意数量的关键字参数"""
for key, value in kwargs.items():
print(f"{key}: {value}")
print_config(host="localhost", port=8080, timeout=30)
# 输出:
# host: localhost
# port: 8080
# timeout: 30
lambda(匿名函数)
Python 使用 lambda 来创建匿名函数。
lambda 函数是一种小型、匿名的、内联函数,它可以具有任意数量的参数,但只能有一个表达式。
匿名函数不需要使用 def 关键字定义完整函数。
lambda 函数通常用于编写简单的、单行的函数,通常在需要函数作为参数传递的情况下使用,
例如在 map()、filter()、reduce() 等函数中。
lambda 函数特点:
- lambda函数是匿名的,它们没有函数名称,只能通过赋值给变量或作为参数传递给其他函数来使用
- lambda 函数通常只包含一行代码,适用于编写简单的函数

案例
"""
Python lambda(匿名函数)
Python 使用 lambda 来创建匿名函数。
lambda 函数是一种小型、匿名的、内联函数,它可以具有任意数量的参数,但只能有一个表达式。
匿名函数不需要使用 def 关键字定义完整函数
公式表达:
lambda arguments: expression
lambda是 Python 的关键字,用于定义 lambda 函数。
arguments 是参数列表,可以包含零个或多个参数,但必须在冒号(:)前指定。
expression 是一个表达式,用于计算并返回函数的结果。
"""
# ab法则
def operator(a, b):
return a + b
def function(a, b, my_lambda_function):
return my_lambda_function(a, b)
print("使用普通函数修改:", function(1, 2, operator))
print("*" * 20)
print("=" * 10, "after", "=" * 10)
def function(a, b, lambda_operator):
return lambda_operator(a, b)
print("使用lambda函数修改:", function(1, 2, lambda a, b: a + b))
print("=" * 20)
# lambda 函数没有参数
f = lambda: "Hello, world!"
print(f()) # 输出: Hello, world!
# lambda 函数1个参数
x = lambda param: param + 10
print(x(5)) # 输出: 15
# lambda 函数多个参数,参数之间使用逗号 , 隔开
x = lambda a, b, c: a + b + c
print(x(5, 6, 2))
# lambda 函数通常与内置函数如 map()、filter() 和 reduce() 一起使用,以便在集合上执行操作
numbers = [1, 2, 3, 4, 5, 6, 7, 8]
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers) # 输出:[2, 4, 6, 8]
'''上述代码对标Java:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
List<Integer> evenNumbers = numbers.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
System.out.println(evenNumbers);'''
# 有三名学生的姓名和年龄,按年龄排序
student_list = [{"name": "z3", "age": 36}, {"name": "li4", "age": 14}, {"name": "w5", "age": 27}]
print(sorted(student_list, key=lambda x: x["age"]))
# map() 的主要作用是将给定的函数批量应用到可迭代对象的每个元素上,实现数据转换
map_result = map(lambda x: x * x, [0, 1, 3, 7, 9])
print(list(map_result)) # [0, 1, 9, 49, 81]
# filter() 的主要作用是将给定的函数**批量应用**到可迭代对象的每个元素上,实现数据过滤
filter_result = filter(lambda x: x >= 0, [-0, -1, -3, 7, 9])
print(list(filter_result)) # [0, 7, 9]
解包(unpacking)
解包 = 将序列(列表、元组、字符串等)的元素,一次性分配给多个变量。
核心价值:
消除索引依赖,用有意义的变量名代替 **<font style="color:rgb(6, 10, 38);">numbers[0]</font>**,提升可读性+可维护性
'''
基本定义
把可迭代对象(list/tuple/str/range/生成器等)里的元素“按位置”或“按名字”
批量赋给左侧变量的语法统称“解包”。
1 函数定义时的“收集”
# *args 收集多余位置参数
# **kwargs 收集多余关键字参数
def f(a,*args, **kwargs):
pass
2 函数调用时的解包
args = (1, 2)
kwargs = {'x': 3, 'y': 4}
func(a,*args, **kwargs) # 等价于 func(100,1, 2, x=3, y=4)
'''
def func(a, *args, **kwargs):
print(a)
print(args)
print(kwargs)
func(100,1,2,3,k1=20, k2=30)
print("*" * 20)
# 解包传参:函数调用时解包
def add(a, b, c):
return a + b + c
args = (1, 2)
kwargs = {"c": 3}
print(add(*args, **kwargs))
print("*" * 20)
def func1(seq:int,*number:int) -> int:
result = 0;
print(seq)
for x in number:
result = result + (x * x)
return result
print(func1(1, *(1,2,3)))
print(func1(2, 1,2,3))
#print(func1(3, (1,2,3)))# TypeError: can't multiply sequence by non-int of type 'tuple'
闭包(Closure)
闭包 = 一个函数 + 它"记住"的外部环境(变量)
Python 闭包是指嵌套内部函数引用了其外部(嵌套)函数的变量 / 参数且内部函数被返回或暴露出去,
从而保留了外部函数的作用域(即使外部函数已执行完毕)的一种函数对象。
简单来说,闭包让内部函数 “记住” 了它诞生时的外部环境变量,即使外部函数已经执行结束,这些变量也不会被销毁。
def outer(x):
def inner(y):
return x + y # inner 闭包了 x
return inner
# 创建闭包
add_5 = outer(5)
print(add_5(3)) # 输出 8
闭包必须同时满足 3 个条件:
- 函数嵌套
- 内部函数引用外部函数的局部变量
- 外部函数把内部函数返回(或当作参数传递出去)
优缺点
优点:封装隐藏数据、持久化状态、简化参数传递,适合实现轻量级的状态保持场景
缺点:内存占用过高、可读性 / 调试性差、循环变量捕获陷阱,使用时需避免持有大数据
价值:闭包是 Python 中实现函数式编程和装饰器的重要基础!
💡 为什么重要:
装饰器 = 闭包的典型应用,是 Python 的核心特性(如 <font style="color:rgb(6, 10, 38);">@staticmethod</font>、<font style="color:rgb(6, 10, 38);">@property</font>)。
"""
简化代码
闭包可以提前捕获外部函数的参数,形成一个参数部分固定的新函数,
简化后续调用,避免重复传入相同参数,提升代码复用性和简洁性。
示例:固化 “问候前缀”,后续只需传入姓名即可。
"""
import random
def create_greeter(prefix):
def greeter(name):
return f"{prefix},{name}!"
return greeter
hello_greeter = create_greeter("你好")
print(hello_greeter)
print(hello_greeter(random.randint(1000, 9999))) # 你好,随机数!(无需重复传入"你好")
# 最终建议:不要写三层嵌套!用最简单的单层闭包。
# 💡 为什么这是最佳实践?
# 避免嵌套函数(减少代码复杂度)
# 调用方式符合直觉(像普通函数一样)
def create_greeter(prefix):
def greeter(name):
def greeter2(age):
return f"{prefix},{name},{age}!"
return greeter2 # 1. 返回 greeter2(在 greeter 内部定义后)
return greeter # 2. 返回 greeter(外部函数)
# 使用方式:
greet = create_greeter("Hello")
greet_name = greet("Alice") # 返回 greeter2
print(greet_name(30)) # 输出: Hello,Alice,30!
# summary
'''
闭包是 Python 中实现函数式编程和装饰器的重要基础!
一句话定义
闭包(closure) =「内部函数」+「定义时所在作用域的变量」——即使外层函数已返回,内部函数仍能记住并访问那些变量。
必须同时满足 3 个条件
函数嵌套
内部函数引用外部函数的局部变量
外部函数把内部函数返回(或当作参数传递出去)
记忆口诀
“外层返回内层,内层抓着外层的局部;
返回的函数带着背包,变量永生不死。”
闭包 = 内部函数 + 引用外部变量 + 外部函数返回内部函数,
'''
def outer(x): # 外部函数
def inner(y): # 内部函数
return x + y # 内部函数引用了外部变量 x
return inner # 返回的是“带背包”的内部函数对象
add_10Var = outer(10) # 外部函数返回内部函数,但 x=10 被 inner 背着
print(add_10Var(7)) # 17
print(add_10Var.__closure__) # 查看闭包保存的变量元组
print(add_10Var.__closure__[0].cell_contents) # 10
# 即使 outer(10) 已经执行结束,x=10 本应被销毁,但由于 inner 引用了它,Python 会将 x 保留在闭包环境中

1755

被折叠的 条评论
为什么被折叠?



