惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
SegmentFault 最新的问题
博客园 - 三生石上(FineUI控件)
WordPress大学
WordPress大学
博客园 - 【当耐特】
月光博客
月光博客
Vercel News
Vercel News
D
Docker
I
InfoQ
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 叶小钗
MongoDB | Blog
MongoDB | Blog
GbyAI
GbyAI
有赞技术团队
有赞技术团队
雷峰网
雷峰网
博客园 - 聂微东
小众软件
小众软件
Y
Y Combinator Blog
腾讯CDC
L
LangChain Blog
The GitHub Blog
The GitHub Blog
宝玉的分享
宝玉的分享
Stack Overflow Blog
Stack Overflow Blog
大猫的无限游戏
大猫的无限游戏
T
The Blog of Author Tim Ferriss

Liu Zijian's Blog | 一个技术博客

使用Certbot自动续签HTTPS证书 使用Filebeat采集Nginx日志到ES Python的协程 Python中的异常 Python中的类和对象 Python的数据结构,推导式、迭代器和生成器 Spring AI集成多模态模型 LangChain4j多模态 LangChain Tools工具使用 Python中的模块和包 Python全局环境和虚拟环境(venv) LangChain Prompt提示词工程 LangChain4j Tools工具使用 基于Dify搭建AI智能体应用 LangChain4j RAG检索增强生成 Spring AI实现MCP Server Spring AI集成MCP Client LangChain4j Prompt提示词工程 Spring AI使用知识库增强对话功能 Spring AI实现一个智能客服 Spring AI实现一个简单的对话机器人 实现MinIO数据的每日备份 自己实现一个DNS服务 简单理解AI智能体 大模型和大模型应用 LangChain开篇 LangChain4j开篇 一个解析Excel2007的POI工具类 DataPermissionInterceptor源码解读 TenantLineInnerInterceptor源码解读
Python的函数
Liu Zijian · 2026-01-10 · via Liu Zijian's Blog | 一个技术博客

1.定义

1.函数代码以def关键字开头,后接函数标识符名称和圆括号()
2.任何传入的参数和自变量必须放在圆括号内,圆括号中定义参数
3.函数内容以冒号:开始,需要缩进
4.return表达式结束函数,返回一个值给调用方,不带表达式的return相当于返回None
5.若暂无函数实现,函数体内写一个pass关键字,可避免语法错误

def 函数名(参数列表):
    函数体
    return 返回值

例:

def greet(name, age):
    print("Hello World")

2.类型注解 Type Hints

Python函数参数不需要声明类型,解释器会自动推断,但是会带来难以理解,隐藏BUG,开发效率低下等问题,因此类型注解通过引入可选的类型信息解决这些问题,明确指出函数和返回值的类型,让代码更加健壮可维护。

在实现复杂逻辑和对外提供公共接口时,都应当使用类型注解

例:
func.py

def greet(name: str, age: int) -> str:
    return f"Hello  World {name}, age {age}"

但是,调用时仍然可以不遵守

func.py

def greet(name: str, age: int) -> str:
    return f"Hello  World {name}, age {age}"

if __name__ == '__main__':
    print( greet('lzj', 12.6) )

此时可以通过mypy工具包,对我们的代码进行检测,会检测出问题

先安装mypy工具 pip install mypy,再进行检测

PS D:\PycharmProjects\python-lang-test> mypy .\func\func.py
func\func.py:5: error: Argument 2 to "greet" has incompatible type "float"; expected "int"  [arg-type]
Found 1 error in 1 file (checked 1 source file)

如果要彻底避免,需要进行严格类型检查

def add(a: int, b: int) -> int:

    if not isinstance(a, int):
        raise TypeError(f"参数a期望类型int,实际传入{type(a).__name__}")
    if not isinstance(b, int):
        raise TypeError(f"参数b期望类型int,实际传入{type(b).__name__}")
    return a + b

result2 = add('5', 3)
print(result2)
Traceback (most recent call last):
  File "D:\PycharmProjects\python-lang-test\func\func.py", line 9, in <module>
    result2 = add('5', 3)
  File "D:\PycharmProjects\python-lang-test\func\func.py", line 4, in add
    raise TypeError(f"参数a期望类型int,实际传入{type(a).__name__}")
TypeError: 参数a期望类型int,实际传入str

在函数返回值是某种特定类型或None时使用Optional,等价于Union[具体类型, None]

例:dic.get(name)可能返回字典的值,也可能在没有值时返回None

from typing import Optional

def age(name: str) -> Optional[int]:
    dic = {'a':16, 'b':17, 'c':18}
    return dic.get(name)

if __name__ == '__main__':
    print(age('dd'))
    print(age('a'))
None
16

3.参数

3.1 位置参数

以正确的形式传入函数,数量要和声明时保持一致

from typing import Optional

def fun(age:int) -> Optional[int]:
    print(age)
    return age

fun(10)

3.2 关键字参数

函数调用使用关键字参数来确定传入的参数值

def fun(age:int, name:str) :
    print(age)
    print(name)

fun(name='lzj', age=10)
10
lzj

单独出现的*是分隔符,这是Python3引入的一个特殊语法,在函数参数列表中,一个单独的*用来分隔位置参数和关键字参数,它本身不接收任何值,只是一个标记,意味着它之后的所有参数都必须用关键字方式传递,不能按位置传,例如:

def init_chat_model(
    model: str | None = None,
    *,
    model_provider: str | None = None,
    configurable_fields: Literal["any"] | list[str] | tuple[str, ...] | None = None,
    config_prefix: str | None = None,
    **kwargs: Any,
) -> BaseChatModel | _ConfigurableModel:

3.3 默认参数

调用函数时,如果没有传递参数,则会使用默认参数

def fun(name:str = "a", age:int = 25) :
    print(f"fun---name:{name} age:{age}")

fun()
fun("zhangliang")
fun("wangqiang", 28)
fun---name:a age:25
fun---name:zhangliang age:25
fun---name:wangqiang age:28

3.4 “*”可变位置参数

加了*的参数会以元组的形式传入,一般这种参数放在参数列表后面

格式:

def fun([普通参数], *var_args_tuple) :
    函数体

例:

def print_info(num, *var_tuple):
    print(num)
    print(var_tuple)

print_info(70,1,2,3,4,5)
print_info(80)
print_info(90,*(1,2,3,4,5))
70
(1, 2, 3, 4, 5)
80
()
90
(1, 2, 3, 4, 5)

如果后面还有参数,必须通过关键字参数传入,如果没有给不定长的参数传参,那么得到的是空元组

def print_info1(seq, *var_tuple, age) :
    print(seq)
    print(var_tuple)
    print(age)

print_info1(1,20,30,40,50, age = 25)

print_info1(70, age = 29)
1
(20, 30, 40, 50)
25
70
()
29

3.5 “**”可变关键字参数

加了两个星号的参数,会以字典的形式传入,“**”可变参数的后面不能再有其他参数,因此“**”可变参数往往在“*”可变参数的后面(如果有的话),并且作为整个参数列表的最后一个参数

调用时,直接在参数列表直接传入键值对

def func(nid, **info):
    print(nid)
    print(info)

    
if __name__ == '__main__':
    func(10, name='苗苗', age=22)
    func(11, name='欣欣', age=27)
10
{'name': '苗苗', 'age': 22}
11
{'name': '欣欣', 'age': 27}

如果要传字典,需要用**前缀,否则报错

if __name__ == '__main__':
    dic = {'name':'苗苗', 'age': 18}
    #func(10, dic) ❌
    func(10, **dic) #✅
    func(10, **{'name':'苗苗', 'age': 18}) #✅

3.6 参数解包/打包

上面出现的*() **{}就是一种解包/打包的写法

概念

  • 打包(Packing):将多个参数合并成一个数据结构(元组或字典)
  • 解包(Unpacking):将一个数据结构拆解成多个参数

异同:

语法 含义 类型 使用场景
*args 可变位置参数 元组 不确定数量的位置参数
**kwargs 可变关键字参数 字典 不确定数量的关键字参数
*args, **kwargs 组合使用 - 通用函数包装、装饰器、继承

总结

  • *args:接收多余的位置参数(arguments)
  • **kwargs:接收多余的关键字参数(keyword arguments)

例:

def func(a, *args, **kwargs):
    print(a)
    print(args)
    print(kwargs)

func(100,1,2,3,k1=20, k2=30)
func(200,*(1,2,3),**{"k1":20, "k2":30})
100
(1, 2, 3)
{'k1': 20, 'k2': 30}
200
(1, 2, 3)
{'k1': 20, 'k2': 30}

例:参数解包

传递参数时,可以将多个实参用*组合为元组,传入形参

def sum_num(a, b, c):
    return a+b+c

if __name__ == '__main__':
    print( sum_num(1, 2, 3) ) #6

    print( sum_num( *(1, 2, 3) ) ) #6

    let_tuple = (1, 2, 3)
    print( sum_num( *let_tuple ) ) #6

4.Lambda匿名函数

python使用lambda来创建匿名函数

  • lambda是一种小型的内联函数,通常只有一行代码
  • 匿名的,只能通过赋值给变量或作为参数传递给其他函数的方式来使用
  • 可以有任意数量的参数,但是只能有一个表达式
  • 不需要使用def关键字定义
  • 通常用于编写简单的单行的函数
  • 通常在函数需要作为参数传递的情况下使用

与java的lambda的区别:通常只有一行代码


组成:

lambda arguments : expression
  • lambda 是python的关键字
  • arguments 参数列表
  • expression 表达式,用于计算并返回结果

例:

某种操作函数operator,传入待操作数a, b以及操作规则func,将1和2以及一个加法计算规则add()传入,令operator函数对两个数进行加法

def add(a, b):
    return a + b

def operator(a, b, func):
    return func(a, b)

print( operator(1, 2, add) ) # 3

add()就无需单独再定义函数,可以匿名成为一个加法计算规则的lambda:lambda x, y: x + y

print( operator(1, 2, lambda x, y: x + y ) ) #3

lambda可以赋给变量,称为函数变量,函数变量保存的是函数类型的值,对函数变量进行调用(加小括号),才能得到对应函数的返回值类型的值

例:

f = lambda: "Hello, world!"
print(f) # <function <lambda> at 0x000002A2226B7C40>
print(f())  # Hello, world!
x = lambda a, b, c : a + b + c
print(x(5, 6, 2)) #13

在python中,lambda通常可以和一些内置函数配合使用,实现一些效果

numbers = [1, 2, 3, 4, 5, 6, 7, 8]
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers)  

# 有三名学生的姓名和年龄,按年龄排序
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)) 

# filter() 的主要作用是将给定的函数**批量应用**到可迭代对象的每个元素上,实现数据过滤
filter_result = filter(lambda x: x >= 0, [-0, -1, -3, 7, 9])
print(list(filter_result))  
[2, 4, 6, 8]
[{'name': 'li4', 'age': 14}, {'name': 'w5', 'age': 27}, {'name': 'z3', 'age': 36}]
[0, 1, 9, 49, 81]
[0, 7, 9]

5.闭包 (Closure)

闭包是python实现函数式编程的重要基础

定义:内部函数引用了嵌套它的外部函数的变量或参数,且内部函数被返回或暴露出去,从而保留了外部函数作用域(即便已经调用完成)的函数对象。

例:定义一个函数lazy_sum(),嵌套一个内部函数inner(),并将内部函数inner()作为返回值返回,并赋值给了num,但是是个函数对象,只有执行num(),内部函数inner()才会执行,将外部函数的参数*args进行累加。在这个过程中lazy_sum()的执行完成后,并没有被释放,参数*args也被保留下来,什么时候内部函数执行了,什么时候真正完成调用。

def lazy_sum(*args):
    def inner():
        result = 0
        for n in args:
            result = result + n
        return result
    #返回函数
    return inner

num = lazy_sum(11, 12)

print(num) # <function lazy_sum.<locals>.inner at 0x0000023A15FD62A0>
print(num()) # 23

print(num.__closure__) #闭包保存的变量元组 (<cell at 0x00000241568DB5E0: tuple object at 0x00000241568E8940>,)
print(num.__closure__[0].cell_contents) # 闭包保存的变量 (11, 12)

例:带参数

def hello(s1):
    def world(s2):
        return s1+' '+s2
    #返回函数
    return world

fun = hello('hello')

print(fun('world')) #hello world
print( hello('hello')('world') ) #hello world

总结:

  • 函数要嵌套,支持多层
  • 内部函数要引用外部函数的局部变量
  • 外部函数将内部函数返回,或作为参数传递

利弊:

  • 优点: 封装隐藏数据和持久化状态,简化参数传递,适合实现轻量级状态保持场景
  • 缺点: 内存占用过高,可读性和可调试性差,存在循环变量捕获陷阱,使用时需要避免持有占用大空间的数据

6.装饰器(Decorators)

装饰器类似Spring AOP,前置/后置通知

装饰器(decorators)是Python中的一种高级功能,它允许你动态地修改函数或类的行为。

装饰器本质上是一种函数,它接受一个函数作为参数并返回一个新的函数或修改原来的函数,可以实现不修改被修饰对象的源码和调用方式的前提下,为其额外添加功能(日志,计时,权限校验等)。

执行原理:

  1. 绑定原函数
  2. 定义额外功能
  3. 替换,返回包装函数
  4. 调用,执行原逻辑+增强逻辑

例:装饰器的实现,使用aop()函数增强hello()函数,aop()函数替换掉原hello()函数,直接调用aop()函数

def aop(func):
    def wrapper():
        print("before")
        func()
        print("after")
    return wrapper

def hello() :
    print('hello world')

if __name__ == '__main__':
    aop(hello)()
before
hello world
after

例:简化写法,@加上一个闭包函数,就能构成一个装饰器函数,语法类似Java中的注解

def aop(func):
    def wrapper():
        print("before")
        func()
        print("after")
    return wrapper

@aop
def hello() :
    print('hello world')

if __name__ == '__main__':
    hello()
before
hello world
after

例:带参数的装饰器

def aop(func):
    def wrapper(*args, **kwargs):
        print("before")
        func(*args, **kwargs)
        print("after")
    return wrapper

@aop
def hello(name) :
    print(f'hello,{name}')

if __name__ == '__main__':
    hello('sxh')