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

推荐订阅源

GbyAI
GbyAI
博客园 - 三生石上(FineUI控件)
S
Securelist
U
Unit 42
The Cloudflare Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Simon Willison's Weblog
Simon Willison's Weblog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
B
Blog
T
Tenable Blog
The Hacker News
The Hacker News
The Register - Security
The Register - Security
IT之家
IT之家
博客园 - 【当耐特】
Spread Privacy
Spread Privacy
P
Privacy & Cybersecurity Law Blog
博客园_首页
T
Tailwind CSS Blog
人人都是产品经理
人人都是产品经理
C
Cybersecurity and Infrastructure Security Agency CISA
Know Your Adversary
Know Your Adversary
NISL@THU
NISL@THU
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
T
Tor Project blog
C
CERT Recently Published Vulnerability Notes
Apple Machine Learning Research
Apple Machine Learning Research
Stack Overflow Blog
Stack Overflow Blog
T
Threat Research - Cisco Blogs
T
The Exploit Database - CXSecurity.com
V
Vulnerabilities – Threatpost
A
Arctic Wolf
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
V
V2EX
aimingoo的专栏
aimingoo的专栏
大猫的无限游戏
大猫的无限游戏
Scott Helme
Scott Helme
L
LINUX DO - 热门话题
Cyberwarzone
Cyberwarzone
V
Visual Studio Blog
月光博客
月光博客
爱范儿
爱范儿
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
美团技术团队
G
GRAHAM CLULEY
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
H
Heimdal Security Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO

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源码解读 BaseMultiTableInnerInterceptor源码解读 Spring AI开篇 SQL解析工具JSQLParser 芋道源码解读之多租户 芋道源码解读之数据权限 芋道源码解读开篇 Java实现将数据导出为Word文档 OA系统的天数该怎样计算 安装MySQL8 安装MySQL5.7 RockyLinux9环境下编译MySQL8 MySQL字符集及底层原理 Java实现LDAP登录 Docker Compose IPv4和IPv6 使用虚拟机安装一个K8s集群 使用GraalVM原生编译打包SpringBoot工程 Nginx防止目录穿越 Java线程的状态 Nginx防盗链设置 使用python将excel表格转换为SQL INSERT Redis的公共操作命令 Redis数据结构之Bitfleid Redis数据结构之Bitmap Redis数据结构之GEO Redis数据结构之Hash Redis数据结构之HyperLogLog Redis数据结构之List Redis数据结构之Set Redis数据结构之Stream Redis数据结构之String Redis数据结构之ZSet 使用python压缩图片 利用Python实现Hexo站点的持续集成 Nginx设置HTTPS监听 firewalld防火墙工具的使用 Linux信号(signal)机制 MySQL5.7x 主从复制 用IP自签发一个HTTPS证书 基于Hexo实现一个静态的个人博客 RockyLinux9环境下编译MySQL5.7 Docker离线安装 MySQL数据定义语言 Docker与联合文件系统 Docker的网络 Docker的镜像操作 MySQL存储过程 MyBatis-Plus开篇 MySQL变量 MySQL视图 MySQL事务 MySQL插入修改和删除 MySQL查询 MySQL系统命令 Docker的容器操作 Docker的安装和配置 Docker容器数据卷 浅谈OAuth2.0授权原理 JVM开篇 浅谈Linux(Unix)的I/O模型 一个通用的CloseableHttpClient工厂类 JUC可重入锁ReentrantLock JUC读写锁ReadWriteLock Java的单例 Java泛型 Java8的新特性 最近最少使用算法(LRU) MySQL函数 SpringBoot配置和启动 volatile作用分析
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')